diff --git a/.changeset/blue-apples-pump.md b/.changeset/blue-apples-pump.md new file mode 100644 index 0000000000..c7bbdbbafc --- /dev/null +++ b/.changeset/blue-apples-pump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Added OwnershipCard, ComponentsGrid and UserProfileCard components to the `overridableComponents`. diff --git a/.changeset/chubby-dots-kiss.md b/.changeset/chubby-dots-kiss.md deleted file mode 100644 index 7a28467725..0000000000 --- a/.changeset/chubby-dots-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed an issue causing TechDocs to not properly handle initial redirect. diff --git a/.changeset/clear-bananas-end.md b/.changeset/clear-bananas-end.md deleted file mode 100644 index 50e722544c..0000000000 --- a/.changeset/clear-bananas-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-graph': patch ---- - -Catalog graph plugin support i18n diff --git a/.changeset/create-app-1753196727.md b/.changeset/create-app-1753196727.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1753196727.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/curly-zoos-thank.md b/.changeset/curly-zoos-thank.md deleted file mode 100644 index ec55b2abb9..0000000000 --- a/.changeset/curly-zoos-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -We are consolidating all css files into a single styles.css in Canon. diff --git a/.changeset/cyan-islands-swim.md b/.changeset/cyan-islands-swim.md deleted file mode 100644 index 396cc6fc68..0000000000 --- a/.changeset/cyan-islands-swim.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': major -'@backstage/create-app': patch ---- - -**BREAKING:** The experimental `catalog.useUrlReadersSearch` configuration flag (introduced in v1.36) has been removed. - -The `UrlReaderProcessor` now always uses the `search` method of `UrlReaders`. Built-in `UrlReaderService` implementations have been updated accordingly. -If you use custom `UrlReaderService` implementations, you need to adapt their `search` method to correctly handle both specific URLs and potential -search patterns (see changes on built-in readers [in the original PR](https://github.com/backstage/backstage/pull/28379/files#diff-68b0452f173ee54bdd40f7b5e047a9cb8bb59200425622c212c217b76dac1d1b)). - -Previous behavior was to call the `search` method only if the parsed Git URL's filename contained a wildcard and use `readUrl` otherwise. Each `UrlReaderService` must implement this logic in the `search` method instead. - -This allows each `UrlReaderService` implementation to check whether it's a search URL (that contains a wildcard pattern) or not using logic that is specific to each provider. diff --git a/.changeset/empty-poets-give.md b/.changeset/empty-poets-give.md deleted file mode 100644 index 2eb63c2ed5..0000000000 --- a/.changeset/empty-poets-give.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Add new `RadioGroup` + `Radio` component to Canon diff --git a/.changeset/evil-phones-unite.md b/.changeset/evil-phones-unite.md new file mode 100644 index 0000000000..9a3e4ff151 --- /dev/null +++ b/.changeset/evil-phones-unite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Support `filter` parameter on the `EntityHeaderBlueprint` diff --git a/.changeset/funny-dancers-start.md b/.changeset/funny-dancers-start.md new file mode 100644 index 0000000000..267585f8b2 --- /dev/null +++ b/.changeset/funny-dancers-start.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Update styling of Tooltip element diff --git a/.changeset/gentle-llamas-press.md b/.changeset/gentle-llamas-press.md deleted file mode 100644 index 9c922d396f..0000000000 --- a/.changeset/gentle-llamas-press.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/backend-test-utils': minor ---- - -Add a standard `toString` on credentials objects diff --git a/.changeset/hot-clowns-behave.md b/.changeset/hot-clowns-behave.md new file mode 100644 index 0000000000..3c7e9dec12 --- /dev/null +++ b/.changeset/hot-clowns-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Adding `type` as an override to the `convertLegacyEntityCardExtension` diff --git a/.changeset/huge-heads-occur.md b/.changeset/huge-heads-occur.md new file mode 100644 index 0000000000..1972037cf0 --- /dev/null +++ b/.changeset/huge-heads-occur.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-azure': patch +--- + +`host` should be optional in `config` schema diff --git a/.changeset/nice-actors-cheer.md b/.changeset/nice-actors-cheer.md new file mode 100644 index 0000000000..918148ffb8 --- /dev/null +++ b/.changeset/nice-actors-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Adding a more sensible default order to the default filters diff --git a/.changeset/nice-crabs-clean.md b/.changeset/nice-crabs-clean.md new file mode 100644 index 0000000000..45690e98aa --- /dev/null +++ b/.changeset/nice-crabs-clean.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Support multiple headers in new frontend system, and don't render a header until the entity has finished loading diff --git a/.changeset/petite-paths-remain.md b/.changeset/petite-paths-remain.md deleted file mode 100644 index a2bef50c80..0000000000 --- a/.changeset/petite-paths-remain.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-node-test-utils': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder-node': patch ---- - -An internal refactor which adds additional types to experimental checkpoints diff --git a/.changeset/pre.json b/.changeset/pre.json index 60eb6ca6ce..d01c42b318 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,206 +2,219 @@ "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.110", - "@backstage/app-defaults": "1.6.3", - "example-app-next": "0.0.24", - "app-next-example-plugin": "0.0.24", - "example-backend": "0.0.39", - "@backstage/backend-app-api": "1.2.4", - "@backstage/backend-defaults": "0.11.0", + "example-app": "0.2.111", + "@backstage/app-defaults": "1.6.4", + "example-app-next": "0.0.25", + "app-next-example-plugin": "0.0.25", + "example-backend": "0.0.40", + "@backstage/backend-app-api": "1.2.5", + "@backstage/backend-defaults": "0.11.1", "@backstage/backend-dev-utils": "0.1.5", - "@backstage/backend-dynamic-feature-service": "0.7.1", - "@backstage/backend-openapi-utils": "0.5.4", - "@backstage/backend-plugin-api": "1.4.0", - "@backstage/backend-test-utils": "1.6.0", - "@backstage/canon": "0.5.0", - "@backstage/catalog-client": "1.10.1", - "@backstage/catalog-model": "1.7.4", - "@backstage/cli": "0.33.0", + "@backstage/backend-dynamic-feature-service": "0.7.2", + "@backstage/backend-openapi-utils": "0.5.5", + "@backstage/backend-plugin-api": "1.4.1", + "@backstage/backend-test-utils": "1.7.0", + "@backstage/canon": "0.6.0", + "@backstage/catalog-client": "1.10.2", + "@backstage/catalog-model": "1.7.5", + "@backstage/cli": "0.33.1", "@backstage/cli-common": "0.1.15", "@backstage/cli-node": "0.2.13", "@backstage/codemods": "0.1.52", - "@backstage/config": "1.3.2", - "@backstage/config-loader": "1.10.1", - "@backstage/core-app-api": "1.17.1", - "@backstage/core-compat-api": "0.4.3", - "@backstage/core-components": "0.17.3", - "@backstage/core-plugin-api": "1.10.8", - "@backstage/create-app": "0.7.0", - "@backstage/dev-utils": "1.1.11", - "e2e-test": "0.2.29", + "@backstage/config": "1.3.3", + "@backstage/config-loader": "1.10.2", + "@backstage/core-app-api": "1.18.0", + "@backstage/core-compat-api": "0.4.4", + "@backstage/core-components": "0.17.4", + "@backstage/core-plugin-api": "1.10.9", + "@backstage/create-app": "0.7.1", + "@backstage/dev-utils": "1.1.12", + "e2e-test": "0.2.30", "@backstage/e2e-test-utils": "0.1.1", "@backstage/errors": "1.2.7", "@backstage/eslint-plugin": "0.1.11", - "@backstage/frontend-app-api": "0.11.3", - "@backstage/frontend-defaults": "0.2.3", - "@backstage/frontend-dynamic-feature-loader": "0.1.2", - "@internal/frontend": "0.0.10", - "@backstage/frontend-plugin-api": "0.10.3", - "@backstage/frontend-test-utils": "0.3.3", - "@backstage/integration": "1.17.0", - "@backstage/integration-aws-node": "0.1.16", - "@backstage/integration-react": "1.2.8", + "@backstage/frontend-app-api": "0.11.4", + "@backstage/frontend-defaults": "0.2.4", + "@backstage/frontend-dynamic-feature-loader": "0.1.3", + "@internal/frontend": "0.0.11", + "@backstage/frontend-plugin-api": "0.10.4", + "@backstage/frontend-test-utils": "0.3.4", + "@backstage/integration": "1.17.1", + "@backstage/integration-aws-node": "0.1.17", + "@backstage/integration-react": "1.2.9", "@internal/opaque": "0.0.1", "@backstage/release-manifests": "0.0.13", - "@backstage/repo-tools": "0.14.0", - "@internal/scaffolder": "0.0.10", - "@techdocs/cli": "1.9.4", - "techdocs-cli-embedded-app": "0.2.109", - "@backstage/test-utils": "1.7.9", - "@backstage/theme": "0.6.6", + "@backstage/repo-tools": "0.15.0", + "@internal/scaffolder": "0.0.11", + "@techdocs/cli": "1.9.5", + "techdocs-cli-embedded-app": "0.2.110", + "@backstage/test-utils": "1.7.10", + "@backstage/theme": "0.6.7", "@backstage/types": "1.2.1", + "@backstage/ui": "0.6.0", "@backstage/version-bridge": "1.0.11", - "yarn-plugin-backstage": "0.0.6", - "@backstage/plugin-api-docs": "0.12.8", + "yarn-plugin-backstage": "0.0.7", + "@backstage/plugin-api-docs": "0.12.9", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.10", - "@backstage/plugin-app": "0.1.10", - "@backstage/plugin-app-backend": "0.5.3", - "@backstage/plugin-app-node": "0.1.34", - "@backstage/plugin-app-visualizer": "0.1.20", - "@backstage/plugin-auth-backend": "0.25.1", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-auth0-provider": "0.2.4", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.4", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-github-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-google-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-guest-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.4", - "@backstage/plugin-auth-backend-module-okta-provider": "0.2.4", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.4", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.4", - "@backstage/plugin-auth-node": "0.6.4", - "@backstage/plugin-auth-react": "0.1.16", - "@backstage/plugin-bitbucket-cloud-common": "0.3.0", - "@backstage/plugin-catalog": "1.31.0", - "@backstage/plugin-catalog-backend": "2.1.0", - "@backstage/plugin-catalog-backend-module-aws": "0.4.12", - "@backstage/plugin-catalog-backend-module-azure": "0.3.6", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.3", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.0", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.0", - "@backstage/plugin-catalog-backend-module-gcp": "0.3.9", - "@backstage/plugin-catalog-backend-module-gerrit": "0.3.3", - "@backstage/plugin-catalog-backend-module-gitea": "0.1.1", - "@backstage/plugin-catalog-backend-module-github": "0.10.0", - "@backstage/plugin-catalog-backend-module-github-org": "0.3.11", - "@backstage/plugin-catalog-backend-module-gitlab": "0.7.0", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.10", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.1", - "@backstage/plugin-catalog-backend-module-ldap": "0.11.6", - "@backstage/plugin-catalog-backend-module-logs": "0.1.11", - "@backstage/plugin-catalog-backend-module-msgraph": "0.7.1", - "@backstage/plugin-catalog-backend-module-openapi": "0.2.11", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.11", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.9", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.1", - "@backstage/plugin-catalog-common": "1.1.4", - "@backstage/plugin-catalog-graph": "0.4.20", - "@backstage/plugin-catalog-import": "0.13.1", - "@backstage/plugin-catalog-node": "1.17.1", - "@backstage/plugin-catalog-react": "1.19.0", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.18", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.8", - "@backstage/plugin-config-schema": "0.1.69", - "@backstage/plugin-devtools": "0.1.28", - "@backstage/plugin-devtools-backend": "0.5.6", - "@backstage/plugin-devtools-common": "0.1.16", - "@backstage/plugin-events-backend": "0.5.3", - "@backstage/plugin-events-backend-module-aws-sqs": "0.4.12", - "@backstage/plugin-events-backend-module-azure": "0.2.21", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.21", - "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.2", - "@backstage/plugin-events-backend-module-gerrit": "0.2.21", - "@backstage/plugin-events-backend-module-github": "0.4.1", - "@backstage/plugin-events-backend-module-gitlab": "0.3.2", - "@backstage/plugin-events-backend-module-google-pubsub": "0.1.1", - "@backstage/plugin-events-backend-module-kafka": "0.1.0", - "@backstage/plugin-events-backend-test-utils": "0.1.45", - "@backstage/plugin-events-node": "0.4.12", - "@internal/plugin-todo-list": "1.0.40", - "@internal/plugin-todo-list-backend": "1.0.40", - "@internal/plugin-todo-list-common": "1.0.25", - "@backstage/plugin-gateway-backend": "1.0.2", - "@backstage/plugin-home": "0.8.9", - "@backstage/plugin-home-react": "0.1.27", - "@backstage/plugin-kubernetes": "0.12.8", - "@backstage/plugin-kubernetes-backend": "0.19.7", - "@backstage/plugin-kubernetes-cluster": "0.0.26", - "@backstage/plugin-kubernetes-common": "0.9.5", - "@backstage/plugin-kubernetes-node": "0.3.1", - "@backstage/plugin-kubernetes-react": "0.5.8", - "@backstage/plugin-mcp-actions-backend": "0.1.0", - "@backstage/plugin-notifications": "0.5.6", - "@backstage/plugin-notifications-backend": "0.5.7", - "@backstage/plugin-notifications-backend-module-email": "0.3.10", - "@backstage/plugin-notifications-backend-module-slack": "0.1.2", - "@backstage/plugin-notifications-common": "0.0.9", - "@backstage/plugin-notifications-node": "0.2.16", - "@backstage/plugin-org": "0.6.40", - "@backstage/plugin-org-react": "0.1.39", - "@backstage/plugin-permission-backend": "0.7.1", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.9", - "@backstage/plugin-permission-common": "0.9.0", - "@backstage/plugin-permission-node": "0.10.1", - "@backstage/plugin-permission-react": "0.4.35", - "@backstage/plugin-proxy-backend": "0.6.3", - "@backstage/plugin-proxy-node": "0.1.5", - "@backstage/plugin-scaffolder": "1.32.0", - "@backstage/plugin-scaffolder-backend": "2.0.0", - "@backstage/plugin-scaffolder-backend-module-azure": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.11", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.10", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.11", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-github": "0.8.0", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.9.2", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.11", - "@backstage/plugin-scaffolder-backend-module-rails": "0.5.10", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.11", - "@backstage/plugin-scaffolder-common": "1.5.11", - "@backstage/plugin-scaffolder-node": "0.9.0", - "@backstage/plugin-scaffolder-node-test-utils": "0.3.0", - "@backstage/plugin-scaffolder-react": "1.17.0", - "@backstage/plugin-search": "1.4.27", - "@backstage/plugin-search-backend": "2.0.3", - "@backstage/plugin-search-backend-module-catalog": "0.3.5", - "@backstage/plugin-search-backend-module-elasticsearch": "1.7.3", - "@backstage/plugin-search-backend-module-explore": "0.3.3", - "@backstage/plugin-search-backend-module-pg": "0.5.45", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.10", - "@backstage/plugin-search-backend-module-techdocs": "0.4.3", - "@backstage/plugin-search-backend-node": "1.3.12", - "@backstage/plugin-search-common": "1.2.18", - "@backstage/plugin-search-react": "1.9.1", - "@backstage/plugin-signals": "0.0.20", - "@backstage/plugin-signals-backend": "0.3.5", - "@backstage/plugin-signals-node": "0.1.21", - "@backstage/plugin-signals-react": "0.0.14", - "@backstage/plugin-techdocs": "1.13.0", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.49", - "@backstage/plugin-techdocs-backend": "2.0.3", + "@backstage/plugin-app": "0.1.11", + "@backstage/plugin-app-backend": "0.5.4", + "@backstage/plugin-app-node": "0.1.35", + "@backstage/plugin-app-visualizer": "0.1.21", + "@backstage/plugin-auth-backend": "0.25.2", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-auth0-provider": "0.2.5", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.5", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-github-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-google-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-guest-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.5", + "@backstage/plugin-auth-backend-module-okta-provider": "0.2.5", + "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.5", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.5", + "@backstage/plugin-auth-node": "0.6.5", + "@backstage/plugin-auth-react": "0.1.17", + "@backstage/plugin-bitbucket-cloud-common": "0.3.1", + "@backstage/plugin-catalog": "1.31.1", + "@backstage/plugin-catalog-backend": "3.0.0", + "@backstage/plugin-catalog-backend-module-aws": "0.4.13", + "@backstage/plugin-catalog-backend-module-azure": "0.3.7", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.4", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.1", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.1", + "@backstage/plugin-catalog-backend-module-gcp": "0.3.10", + "@backstage/plugin-catalog-backend-module-gerrit": "0.3.4", + "@backstage/plugin-catalog-backend-module-gitea": "0.1.2", + "@backstage/plugin-catalog-backend-module-github": "0.10.1", + "@backstage/plugin-catalog-backend-module-github-org": "0.3.12", + "@backstage/plugin-catalog-backend-module-gitlab": "0.7.1", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.11", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.2", + "@backstage/plugin-catalog-backend-module-ldap": "0.11.7", + "@backstage/plugin-catalog-backend-module-logs": "0.1.12", + "@backstage/plugin-catalog-backend-module-msgraph": "0.7.2", + "@backstage/plugin-catalog-backend-module-openapi": "0.2.12", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.12", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.10", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.2", + "@backstage/plugin-catalog-common": "1.1.5", + "@backstage/plugin-catalog-graph": "0.4.21", + "@backstage/plugin-catalog-import": "0.13.3", + "@backstage/plugin-catalog-node": "1.17.2", + "@backstage/plugin-catalog-react": "1.19.1", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.19", + "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.9", + "@backstage/plugin-config-schema": "0.1.70", + "@backstage/plugin-devtools": "0.1.29", + "@backstage/plugin-devtools-backend": "0.5.7", + "@backstage/plugin-devtools-common": "0.1.17", + "@backstage/plugin-events-backend": "0.5.4", + "@backstage/plugin-events-backend-module-aws-sqs": "0.4.13", + "@backstage/plugin-events-backend-module-azure": "0.2.22", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.22", + "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.3", + "@backstage/plugin-events-backend-module-gerrit": "0.2.22", + "@backstage/plugin-events-backend-module-github": "0.4.2", + "@backstage/plugin-events-backend-module-gitlab": "0.3.3", + "@backstage/plugin-events-backend-module-google-pubsub": "0.1.2", + "@backstage/plugin-events-backend-module-kafka": "0.1.1", + "@backstage/plugin-events-backend-test-utils": "0.1.46", + "@backstage/plugin-events-node": "0.4.13", + "@internal/plugin-todo-list": "1.0.41", + "@internal/plugin-todo-list-backend": "1.0.41", + "@internal/plugin-todo-list-common": "1.0.26", + "@backstage/plugin-gateway-backend": "1.0.3", + "@backstage/plugin-home": "0.8.10", + "@backstage/plugin-home-react": "0.1.28", + "@backstage/plugin-kubernetes": "0.12.9", + "@backstage/plugin-kubernetes-backend": "0.19.8", + "@backstage/plugin-kubernetes-cluster": "0.0.27", + "@backstage/plugin-kubernetes-common": "0.9.6", + "@backstage/plugin-kubernetes-node": "0.3.2", + "@backstage/plugin-kubernetes-react": "0.5.9", + "@backstage/plugin-mcp-actions-backend": "0.1.1", + "@backstage/plugin-notifications": "0.5.7", + "@backstage/plugin-notifications-backend": "0.5.8", + "@backstage/plugin-notifications-backend-module-email": "0.3.11", + "@backstage/plugin-notifications-backend-module-slack": "0.1.3", + "@backstage/plugin-notifications-common": "0.0.10", + "@backstage/plugin-notifications-node": "0.2.17", + "@backstage/plugin-org": "0.6.41", + "@backstage/plugin-org-react": "0.1.40", + "@backstage/plugin-permission-backend": "0.7.2", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.10", + "@backstage/plugin-permission-common": "0.9.1", + "@backstage/plugin-permission-node": "0.10.2", + "@backstage/plugin-permission-react": "0.4.36", + "@backstage/plugin-proxy-backend": "0.6.4", + "@backstage/plugin-proxy-node": "0.1.6", + "@backstage/plugin-scaffolder": "1.33.0", + "@backstage/plugin-scaffolder-backend": "2.1.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.12", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.11", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.13", + "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-github": "0.8.1", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.9.3", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.12", + "@backstage/plugin-scaffolder-backend-module-rails": "0.5.11", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.12", + "@backstage/plugin-scaffolder-common": "1.6.0", + "@backstage/plugin-scaffolder-node": "0.10.0", + "@backstage/plugin-scaffolder-node-test-utils": "0.3.1", + "@backstage/plugin-scaffolder-react": "1.18.0", + "@backstage/plugin-search": "1.4.28", + "@backstage/plugin-search-backend": "2.0.4", + "@backstage/plugin-search-backend-module-catalog": "0.3.6", + "@backstage/plugin-search-backend-module-elasticsearch": "1.7.4", + "@backstage/plugin-search-backend-module-explore": "0.3.4", + "@backstage/plugin-search-backend-module-pg": "0.5.46", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.11", + "@backstage/plugin-search-backend-module-techdocs": "0.4.4", + "@backstage/plugin-search-backend-node": "1.3.13", + "@backstage/plugin-search-common": "1.2.19", + "@backstage/plugin-search-react": "1.9.2", + "@backstage/plugin-signals": "0.0.21", + "@backstage/plugin-signals-backend": "0.3.6", + "@backstage/plugin-signals-node": "0.1.22", + "@backstage/plugin-signals-react": "0.0.15", + "@backstage/plugin-techdocs": "1.13.2", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.51", + "@backstage/plugin-techdocs-backend": "2.0.4", "@backstage/plugin-techdocs-common": "0.1.1", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.25", - "@backstage/plugin-techdocs-node": "1.13.4", - "@backstage/plugin-techdocs-react": "1.3.0", - "@backstage/plugin-user-settings": "0.8.23", - "@backstage/plugin-user-settings-backend": "0.3.3", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.26", + "@backstage/plugin-techdocs-node": "1.13.5", + "@backstage/plugin-techdocs-react": "1.3.1", + "@backstage/plugin-user-settings": "0.8.24", + "@backstage/plugin-user-settings-backend": "0.3.4", "@backstage/plugin-user-settings-common": "0.0.1" }, - "changesets": [] + "changesets": [ + "blue-apples-pump", + "create-app-1753196727", + "evil-phones-unite", + "funny-dancers-start", + "hot-clowns-behave", + "huge-heads-occur", + "nice-actors-cheer", + "nice-crabs-clean", + "spotty-icons-shake", + "tender-crabs-stay", + "twenty-pumas-brush" + ] } diff --git a/.changeset/public-nails-melt.md b/.changeset/public-nails-melt.md deleted file mode 100644 index 1529ee94d0..0000000000 --- a/.changeset/public-nails-melt.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/canon': minor ---- - -**BREAKING CHANGES** - -We’re updating our Button component to provide better support for button links. - -- We’re introducing a new `ButtonLink` component, which replaces the previous render prop pattern. -- To maintain naming consistency across components, `IconButton` is being renamed to `ButtonIcon`. -- Additionally, the render prop will be removed from all button-related components. - -These changes aim to simplify usage and improve clarity in our component API. diff --git a/.changeset/rich-eagles-rule.md b/.changeset/rich-eagles-rule.md deleted file mode 100644 index 100ccafb77..0000000000 --- a/.changeset/rich-eagles-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-mcp-actions-backend': patch ---- - -Fixed the example in the README for generating a static token by adding a subject field diff --git a/.changeset/sharp-stars-report.md b/.changeset/sharp-stars-report.md deleted file mode 100644 index c37e0e39ea..0000000000 --- a/.changeset/sharp-stars-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Replaced deprecated uses of `@backstage/backend-common` with the equivalents in `@backstage/backend-defaults` and `@backstage/backend-plugin-api`. diff --git a/.changeset/silent-vans-tie.md b/.changeset/silent-vans-tie.md deleted file mode 100644 index b81564be7e..0000000000 --- a/.changeset/silent-vans-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Added placeholder prop to TextField component. diff --git a/.changeset/sixty-ties-matter.md b/.changeset/sixty-ties-matter.md deleted file mode 100644 index 3be0bb08a8..0000000000 --- a/.changeset/sixty-ties-matter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch ---- - -Fixing the typescript issue with using `z.unknown()` diff --git a/.changeset/spotty-icons-shake.md b/.changeset/spotty-icons-shake.md new file mode 100644 index 0000000000..0c4f318cd9 --- /dev/null +++ b/.changeset/spotty-icons-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-defaults': patch +--- + +Added support for passing through `allowUnknownExtensionConfig` as a flag diff --git a/.changeset/stupid-donuts-sit.md b/.changeset/stupid-donuts-sit.md deleted file mode 100644 index e829d49843..0000000000 --- a/.changeset/stupid-donuts-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Fixed bug with error message since ResponseError is now thrown from CatalogClient diff --git a/.changeset/tender-crabs-stay.md b/.changeset/tender-crabs-stay.md new file mode 100644 index 0000000000..ac3296ea4e --- /dev/null +++ b/.changeset/tender-crabs-stay.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': minor +--- + +**Breaking** We are upgrading our `Text` component to support all font sizes making the `Heading` component redundant. The new `Text` component introduces 4 sizes for title and 4 sizes for body text. All of these work in multiple colors and font weights. We improved the `as` prop to include all possible values. The `Link` component has also been updated to match the new `Text` component. diff --git a/.changeset/three-shoes-behave.md b/.changeset/three-shoes-behave.md deleted file mode 100644 index 51205ffa21..0000000000 --- a/.changeset/three-shoes-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -adding export for ButtonLink so it's importable diff --git a/.changeset/tired-bats-attend.md b/.changeset/tired-bats-attend.md deleted file mode 100644 index cfe01f14fe..0000000000 --- a/.changeset/tired-bats-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration-react': patch ---- - -Separated gitlab `write_repository` and `api` scope to pass checks in `RefreshingAuthSessionManager` diff --git a/.changeset/twenty-pumas-brush.md b/.changeset/twenty-pumas-brush.md new file mode 100644 index 0000000000..6306fe0607 --- /dev/null +++ b/.changeset/twenty-pumas-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Adds onTabSelectionChange to ui header component. diff --git a/.changeset/wicked-socks-share.md b/.changeset/wicked-socks-share.md deleted file mode 100644 index d3e1275732..0000000000 --- a/.changeset/wicked-socks-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend': patch ---- - -Error messages should not contain backend SQL query strings in the API response, this change will ensure that messages are logged and empty response is returned to the user diff --git a/.changeset/wise-frogs-talk.md b/.changeset/wise-frogs-talk.md deleted file mode 100644 index 6a25abc246..0000000000 --- a/.changeset/wise-frogs-talk.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/integration': patch ---- - -Fixed bug where the GitLab user token and GitLab integration token were being merged together diff --git a/.eslintignore b/.eslintignore index ea8f6760c7..5cfe8188d3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,7 +7,7 @@ **/.git/** **/public/** **/microsite/** -**/canon-docs/** +**/docs-ui/** **/templates/** **/sample-templates/** playwright.config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2685926549..519204ff24 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -40,6 +40,7 @@ yarn.lock @backstage/maintainers @backst /packages/repo-tools @backstage/tooling-maintainers /packages/techdocs-cli @backstage/techdocs-maintainers /packages/techdocs-cli-embedded-app @backstage/techdocs-maintainers +/packages/ui @backstage/design-system-maintainers /packages/yarn-plugin @backstage/tooling-maintainers /plugins/app @backstage/framework-maintainers /plugins/app-* @backstage/framework-maintainers diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..4f0e0ac47d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,31 @@ +This is a TypeScript project structured as a monorepo using Yarn workspaces. + +## Code Standards + +The following files contain guidelines for the project: + +- `/STYLE.md`: guidelines for code style. +- `/REVIEWING.md`: guidelines for pull requests. +- `/SECURITY.md`: guidelines for security. +- `/docs/architecture-decisions/`: contains the architecture decisions for the project. + +## Development Flow + +Before any of these commands can be run, you need to run `yarn install` in the project root. + +- Build: There is no need to build the project during development, and it is verified automatically in the CI pipeline. +- Test: Use `yarn test ` in the project root to run tests. The path can be either a single file or a directory, and be omitted to run tests for all changed files. +- Type checking: Use `yarn tsc` in the project root to run the type checker. +- 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. + +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. + +Never update ESLint, Prettier, or TypeScript configuration files unless specifically requested. + +## Repository Structure + +See `/docs/contribute/project-structure.md` for a detailed description of the repository structure. diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 92c7a293f5..430e76a2ce 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -10,6 +10,7 @@ Airbrakes ajv Alaria Alef +allowedHosts allowlisted Anddddd Apdex @@ -43,6 +44,7 @@ bugfixes builtins bundler bundlers +bursty callout CDNs Chai @@ -102,6 +104,8 @@ deliverables denormalized dependabot deps +dequeue +dequeueing deserialization destructured destructuring @@ -111,8 +115,6 @@ devcontainer devcontainers devops devs -dequeue -dequeueing dialogs disambiguator discoverability @@ -150,8 +152,8 @@ FireHydrant Firekube Firestore Fiverr -Flightcontrol flightcontrol +Flightcontrol Francesco Frontside Gaurav @@ -175,8 +177,8 @@ Hackathons haproxy hardcoded hardcoding -Harness harness +Harness Helidon Henneke Heroku @@ -199,9 +201,10 @@ Indal indexable ingestors inlined -inlining inlinehilite +inlining integrator's +intellij interop interoperate iterable @@ -312,8 +315,8 @@ OpenSearch OpenShift openssl orgs -Overridable overridable +Overridable padding paddings pagerduty @@ -380,10 +383,10 @@ retryable reusability Reusability roadmaps -rollbar -rollout Roboto +rollbar Rollbar +rollout Rollup routable Routable @@ -399,9 +402,10 @@ sanitization scaffolded scaffolder Scaffolder -scrollbar SCM SCMs +scrollable +scrollbar sdks seb semlas @@ -409,14 +413,15 @@ semver sendmail serializable Serverless +severities shoutout SIG signoff SIGs siloed Sinon -snackbars snackbar +snackbars Snyk Sonarqube sourcemaps @@ -487,6 +492,7 @@ transpiled transpiler transpilers truthy +tsconfig TSDoc typeahead ui @@ -537,7 +543,3 @@ zod Zolotusky zoomable zsh -scrollable -severities -intellij -tsconfig diff --git a/.github/workflows/api-breaking-changes-comment.yml b/.github/workflows/api-breaking-changes-comment.yml index af625f67ab..937e035470 100644 --- a/.github/workflows/api-breaking-changes-comment.yml +++ b/.github/workflows/api-breaking-changes-comment.yml @@ -23,7 +23,7 @@ jobs: comment-cache-key: ${{ steps.hash.outputs.COMMENT_FILE_HASH }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: disable-sudo: true egress-policy: block diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml index 74473f30d5..a4e9b57939 100644 --- a/.github/workflows/api-breaking-changes.yml +++ b/.github/workflows/api-breaking-changes.yml @@ -14,7 +14,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index ec6dd0c85c..32131b1b92 100644 --- a/.github/workflows/automate_area-labels.yml +++ b/.github/workflows/automate_area-labels.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index c1245c59b9..8e82bb9572 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml index ebe2ef739d..4aa923fc93 100644 --- a/.github/workflows/automate_merge_message.yml +++ b/.github/workflows/automate_merge_message.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index 6be74ae99f..e281d7be79 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml index 472a7a4e72..2ddb6e79df 100644 --- a/.github/workflows/ci-noop.yml +++ b/.github/workflows/ci-noop.yml @@ -40,7 +40,7 @@ jobs: name: Test ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 059596265e..bdf6edbbac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: name: Install ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -64,7 +64,7 @@ jobs: name: Verify ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -131,6 +131,10 @@ jobs: - name: build canon run: yarn --cwd packages/canon build + # For now BUI has a custom build script and needs to be built separately + - name: build BUI + run: yarn --cwd packages/ui build + - name: verify type dependencies run: yarn lint:type-deps diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index b48bd2683d..4204b18864 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 10 steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 9c97c62d16..c741f23873 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index a5e89d6103..164da4f2e8 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -135,7 +135,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -246,7 +246,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index b1d79713a4..3f24fcc783 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -114,6 +114,10 @@ jobs: - name: build canon run: yarn --cwd packages/canon build + # For now BUI has a custom build script and needs to be built separately + - name: build BUI + run: yarn --cwd packages/ui build + - name: verify type dependencies run: yarn lint:type-deps @@ -151,7 +155,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 50d0e4ceb0..a073ece267 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -16,7 +16,7 @@ jobs: if: github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml index e2bdb4c1cb..c3bc767379 100644 --- a/.github/workflows/pr-review-comment-trigger.yaml +++ b/.github/workflows/pr-review-comment-trigger.yaml @@ -20,7 +20,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index e108f3a4d7..e922db9550 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -17,7 +17,7 @@ jobs: steps: # Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index ab2630c2d9..cbfdb3b1e9 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -18,7 +18,7 @@ jobs: if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 45eb5de5c8..e0ab6aacc1 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_canon.yml b/.github/workflows/sync_canon.yml index 2177177df0..5abae892f6 100644 --- a/.github/workflows/sync_canon.yml +++ b/.github/workflows/sync_canon.yml @@ -4,11 +4,11 @@ on: branches: [master] jobs: - sync-canon-docs: + sync-docs-ui: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -26,11 +26,11 @@ jobs: with: cache-prefix: ${{ runner.os }}-v20.x - - name: Checkout backstage/canon-docs + - name: Checkout backstage/docs-ui uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - repository: backstage/canon-docs - path: canon-external-docs + repository: backstage/docs-ui + path: bui-external-docs token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - name: Configure Git @@ -39,22 +39,22 @@ jobs: git config --global user.name 'Github Canon Docs workflow' - name: Install dependencies - working-directory: canon-docs + working-directory: docs-ui run: yarn install - - name: Build Canon Docs - working-directory: canon-docs + - name: Build Docs UI + working-directory: docs-ui run: | yarn build - - name: Replace contents of canon-external-docs repo with docs build output - working-directory: canon-external-docs + - name: Replace contents of bui-external-docs repo with docs build output + working-directory: bui-external-docs run: | git rm -rf . - cp -R ../canon-docs/dist/. . + cp -R ../docs-ui/dist/. . - name: Commit to canon-storybook repo - working-directory: canon-external-docs + working-directory: bui-external-docs run: | git add . git commit -am "Canon Docs build for backstage/backstage@${{ github.sha }}" diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 18ec62c7bf..93a78a894f 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index 42efaa1142..8fab209548 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index 1c9d37aef0..49ba9950fb 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index 2eb8f13dbc..8a6eacf36e 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index b7cc0b33c7..406b99b129 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index 741471d558..0ca407283f 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml index 42dadb5a57..2fb34431ad 100644 --- a/.github/workflows/sync_version-packages.yml +++ b/.github/workflows/sync_version-packages.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml index c33acfd86d..9d517e8021 100644 --- a/.github/workflows/verify_accessibility-noop.yml +++ b/.github/workflows/verify_accessibility-noop.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml index 02a303f9ea..b4987d28b4 100644 --- a/.github/workflows/verify_accessibility.yml +++ b/.github/workflows/verify_accessibility.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index c4b21a9e1f..0098eec8f2 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index a3b80f498a..b6bd21e04e 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml index 65fc6eccc9..3c3e631082 100644 --- a/.github/workflows/verify_e2e-linux-noop.yml +++ b/.github/workflows/verify_e2e-linux-noop.yml @@ -29,7 +29,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 0995a85216..840af4806c 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -43,7 +43,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index fc30b377bc..6284bc14ea 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -32,7 +32,7 @@ jobs: name: Techdocs steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows-noop.yml b/.github/workflows/verify_e2e-windows-noop.yml index e713f33ed6..2088ce86ff 100644 --- a/.github/workflows/verify_e2e-windows-noop.yml +++ b/.github/workflows/verify_e2e-windows-noop.yml @@ -25,7 +25,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index 0dc0bdaade..cd58c42dc1 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -33,7 +33,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml index 7bc612bf64..30a1eccebc 100644 --- a/.github/workflows/verify_fossa.yml +++ b/.github/workflows/verify_fossa.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml index da4bc6ba25..218a9bd992 100644 --- a/.github/workflows/verify_microsite-noop.yml +++ b/.github/workflows/verify_microsite-noop.yml @@ -21,7 +21,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index 38900074d6..e8bb1924cc 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -28,7 +28,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -137,7 +137,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -240,7 +240,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite_accessibility-noop.yml b/.github/workflows/verify_microsite_accessibility-noop.yml index d6f9d24b5e..c66ff0dc4e 100644 --- a/.github/workflows/verify_microsite_accessibility-noop.yml +++ b/.github/workflows/verify_microsite_accessibility-noop.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite_accessibility.yml b/.github/workflows/verify_microsite_accessibility.yml index ee841f6fa8..05701231dc 100644 --- a/.github/workflows/verify_microsite_accessibility.yml +++ b/.github/workflows/verify_microsite_accessibility.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml index 392a218a83..9f66456edd 100644 --- a/.github/workflows/verify_storybook-noop.yml +++ b/.github/workflows/verify_storybook-noop.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 6c1ceb4c52..013b1cf069 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -49,10 +49,10 @@ jobs: run: yarn install --immutable working-directory: storybook - # Only for verification, the canon one is what we upload to Chromatic + # Only for verification, the BUI one is what we upload to Chromatic - run: yarn build-storybook - - run: yarn --cwd packages/canon build-storybook + - run: yarn --cwd packages/ui build-storybook - uses: chromaui/action@1cfa065cbdab28f6ca3afaeb3d761383076a35aa # v11 with: @@ -60,5 +60,5 @@ jobs: # projectToken intentionally shared to allow collaborators to run Chromatic on forks # https://www.chromatic.com/docs/custom-ci-provider#run-chromatic-on-external-forks-of-open-source-projects projectToken: chpt_dab72dc0f97d55b - workingDir: packages/canon + workingDir: packages/ui storybookBuildDir: storybook-static diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index d7b172256d..0ef88d473b 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit diff --git a/.prettierignore b/.prettierignore index 04ca7d780d..718387ef22 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,10 +1,10 @@ .yarn dist microsite -canon-docs/.next -canon-docs/public -canon-docs/out -packages/canon/css +docs-ui/.next +docs-ui/public +docs-ui/out +packages/ui/css coverage *.hbs templates diff --git a/canon-docs/public/CNAME b/canon-docs/public/CNAME deleted file mode 100644 index 01f6d196cc..0000000000 --- a/canon-docs/public/CNAME +++ /dev/null @@ -1 +0,0 @@ -canon.backstage.io \ No newline at end of file diff --git a/canon-docs/public/header.png b/canon-docs/public/header.png deleted file mode 100644 index 8d11151a3e..0000000000 Binary files a/canon-docs/public/header.png and /dev/null differ diff --git a/canon-docs/public/styles.css b/canon-docs/public/styles.css deleted file mode 100644 index c4c9ca5566..0000000000 --- a/canon-docs/public/styles.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ -@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}}.cu-p{padding:var(--p)}.cu-p-0\.5{padding:var(--canon-space-0_5)}.cu-p-1{padding:var(--canon-space-1)}.cu-p-1\.5{padding:var(--canon-space-1_5)}.cu-p-2{padding:var(--canon-space-2)}.cu-p-3{padding:var(--canon-space-3)}.cu-p-4{padding:var(--canon-space-4)}.cu-p-5{padding:var(--canon-space-5)}.cu-p-6{padding:var(--canon-space-6)}.cu-p-7{padding:var(--canon-space-7)}.cu-p-8{padding:var(--canon-space-8)}.cu-p-9{padding:var(--canon-space-9)}.cu-p-10{padding:var(--canon-space-10)}.cu-p-11{padding:var(--canon-space-11)}.cu-p-12{padding:var(--canon-space-12)}.cu-p-13{padding:var(--canon-space-13)}.cu-p-14{padding:var(--canon-space-14)}@media (width>=640px){.xs\:cu-p{padding:var(--p-xs)}.xs\:cu-p-0\.5{padding:var(--canon-space-0_5)}.xs\:cu-p-1{padding:var(--canon-space-1)}.xs\:cu-p-1\.5{padding:var(--canon-space-1_5)}.xs\:cu-p-2{padding:var(--canon-space-2)}.xs\:cu-p-3{padding:var(--canon-space-3)}.xs\:cu-p-4{padding:var(--canon-space-4)}.xs\:cu-p-5{padding:var(--canon-space-5)}.xs\:cu-p-6{padding:var(--canon-space-6)}.xs\:cu-p-7{padding:var(--canon-space-7)}.xs\:cu-p-8{padding:var(--canon-space-8)}.xs\:cu-p-9{padding:var(--canon-space-9)}.xs\:cu-p-10{padding:var(--canon-space-10)}.xs\:cu-p-11{padding:var(--canon-space-11)}.xs\:cu-p-12{padding:var(--canon-space-12)}.xs\:cu-p-13{padding:var(--canon-space-13)}.xs\:cu-p-14{padding:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-p{padding:var(--p-sm)}.sm\:cu-p-0\.5{padding:var(--canon-space-0_5)}.sm\:cu-p-1{padding:var(--canon-space-1)}.sm\:cu-p-1\.5{padding:var(--canon-space-1_5)}.sm\:cu-p-2{padding:var(--canon-space-2)}.sm\:cu-p-3{padding:var(--canon-space-3)}.sm\:cu-p-4{padding:var(--canon-space-4)}.sm\:cu-p-5{padding:var(--canon-space-5)}.sm\:cu-p-6{padding:var(--canon-space-6)}.sm\:cu-p-7{padding:var(--canon-space-7)}.sm\:cu-p-8{padding:var(--canon-space-8)}.sm\:cu-p-9{padding:var(--canon-space-9)}.sm\:cu-p-10{padding:var(--canon-space-10)}.sm\:cu-p-11{padding:var(--canon-space-11)}.sm\:cu-p-12{padding:var(--canon-space-12)}.sm\:cu-p-13{padding:var(--canon-space-13)}.sm\:cu-p-14{padding:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-p{padding:var(--p-md)}.md\:cu-p-0\.5{padding:var(--canon-space-0_5)}.md\:cu-p-1{padding:var(--canon-space-1)}.md\:cu-p-1\.5{padding:var(--canon-space-1_5)}.md\:cu-p-2{padding:var(--canon-space-2)}.md\:cu-p-3{padding:var(--canon-space-3)}.md\:cu-p-4{padding:var(--canon-space-4)}.md\:cu-p-5{padding:var(--canon-space-5)}.md\:cu-p-6{padding:var(--canon-space-6)}.md\:cu-p-7{padding:var(--canon-space-7)}.md\:cu-p-8{padding:var(--canon-space-8)}.md\:cu-p-9{padding:var(--canon-space-9)}.md\:cu-p-10{padding:var(--canon-space-10)}.md\:cu-p-11{padding:var(--canon-space-11)}.md\:cu-p-12{padding:var(--canon-space-12)}.md\:cu-p-13{padding:var(--canon-space-13)}.md\:cu-p-14{padding:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-p{padding:var(--p-lg)}.lg\:cu-p-0\.5{padding:var(--canon-space-0_5)}.lg\:cu-p-1{padding:var(--canon-space-1)}.lg\:cu-p-1\.5{padding:var(--canon-space-1_5)}.lg\:cu-p-2{padding:var(--canon-space-2)}.lg\:cu-p-3{padding:var(--canon-space-3)}.lg\:cu-p-4{padding:var(--canon-space-4)}.lg\:cu-p-5{padding:var(--canon-space-5)}.lg\:cu-p-6{padding:var(--canon-space-6)}.lg\:cu-p-7{padding:var(--canon-space-7)}.lg\:cu-p-8{padding:var(--canon-space-8)}.lg\:cu-p-9{padding:var(--canon-space-9)}.lg\:cu-p-10{padding:var(--canon-space-10)}.lg\:cu-p-11{padding:var(--canon-space-11)}.lg\:cu-p-12{padding:var(--canon-space-12)}.lg\:cu-p-13{padding:var(--canon-space-13)}.lg\:cu-p-14{padding:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-p{padding:var(--p-xl)}.xl\:cu-p-0\.5{padding:var(--canon-space-0_5)}.xl\:cu-p-1{padding:var(--canon-space-1)}.xl\:cu-p-1\.5{padding:var(--canon-space-1_5)}.xl\:cu-p-2{padding:var(--canon-space-2)}.xl\:cu-p-3{padding:var(--canon-space-3)}.xl\:cu-p-4{padding:var(--canon-space-4)}.xl\:cu-p-5{padding:var(--canon-space-5)}.xl\:cu-p-6{padding:var(--canon-space-6)}.xl\:cu-p-7{padding:var(--canon-space-7)}.xl\:cu-p-8{padding:var(--canon-space-8)}.xl\:cu-p-9{padding:var(--canon-space-9)}.xl\:cu-p-10{padding:var(--canon-space-10)}.xl\:cu-p-11{padding:var(--canon-space-11)}.xl\:cu-p-12{padding:var(--canon-space-12)}.xl\:cu-p-13{padding:var(--canon-space-13)}.xl\:cu-p-14{padding:var(--canon-space-14)}}.cu-pl{padding-left:var(--pl)}.cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.cu-pl-1{padding-left:var(--canon-space-1)}.cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.cu-pl-2{padding-left:var(--canon-space-2)}.cu-pl-3{padding-left:var(--canon-space-3)}.cu-pl-4{padding-left:var(--canon-space-4)}.cu-pl-5{padding-left:var(--canon-space-5)}.cu-pl-6{padding-left:var(--canon-space-6)}.cu-pl-7{padding-left:var(--canon-space-7)}.cu-pl-8{padding-left:var(--canon-space-8)}.cu-pl-9{padding-left:var(--canon-space-9)}.cu-pl-10{padding-left:var(--canon-space-10)}.cu-pl-11{padding-left:var(--canon-space-11)}.cu-pl-12{padding-left:var(--canon-space-12)}.cu-pl-13{padding-left:var(--canon-space-13)}.cu-pl-14{padding-left:var(--canon-space-14)}@media (width>=640px){.xs\:cu-pl{padding-left:var(--pl-xs)}.xs\:cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.xs\:cu-pl-1{padding-left:var(--canon-space-1)}.xs\:cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.xs\:cu-pl-2{padding-left:var(--canon-space-2)}.xs\:cu-pl-3{padding-left:var(--canon-space-3)}.xs\:cu-pl-4{padding-left:var(--canon-space-4)}.xs\:cu-pl-5{padding-left:var(--canon-space-5)}.xs\:cu-pl-6{padding-left:var(--canon-space-6)}.xs\:cu-pl-7{padding-left:var(--canon-space-7)}.xs\:cu-pl-8{padding-left:var(--canon-space-8)}.xs\:cu-pl-9{padding-left:var(--canon-space-9)}.xs\:cu-pl-10{padding-left:var(--canon-space-10)}.xs\:cu-pl-11{padding-left:var(--canon-space-11)}.xs\:cu-pl-12{padding-left:var(--canon-space-12)}.xs\:cu-pl-13{padding-left:var(--canon-space-13)}.xs\:cu-pl-14{padding-left:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-pl{padding-left:var(--pl-sm)}.sm\:cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.sm\:cu-pl-1{padding-left:var(--canon-space-1)}.sm\:cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.sm\:cu-pl-2{padding-left:var(--canon-space-2)}.sm\:cu-pl-3{padding-left:var(--canon-space-3)}.sm\:cu-pl-4{padding-left:var(--canon-space-4)}.sm\:cu-pl-5{padding-left:var(--canon-space-5)}.sm\:cu-pl-6{padding-left:var(--canon-space-6)}.sm\:cu-pl-7{padding-left:var(--canon-space-7)}.sm\:cu-pl-8{padding-left:var(--canon-space-8)}.sm\:cu-pl-9{padding-left:var(--canon-space-9)}.sm\:cu-pl-10{padding-left:var(--canon-space-10)}.sm\:cu-pl-11{padding-left:var(--canon-space-11)}.sm\:cu-pl-12{padding-left:var(--canon-space-12)}.sm\:cu-pl-13{padding-left:var(--canon-space-13)}.sm\:cu-pl-14{padding-left:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-pl{padding-left:var(--pl-md)}.md\:cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.md\:cu-pl-1{padding-left:var(--canon-space-1)}.md\:cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.md\:cu-pl-2{padding-left:var(--canon-space-2)}.md\:cu-pl-3{padding-left:var(--canon-space-3)}.md\:cu-pl-4{padding-left:var(--canon-space-4)}.md\:cu-pl-5{padding-left:var(--canon-space-5)}.md\:cu-pl-6{padding-left:var(--canon-space-6)}.md\:cu-pl-7{padding-left:var(--canon-space-7)}.md\:cu-pl-8{padding-left:var(--canon-space-8)}.md\:cu-pl-9{padding-left:var(--canon-space-9)}.md\:cu-pl-10{padding-left:var(--canon-space-10)}.md\:cu-pl-11{padding-left:var(--canon-space-11)}.md\:cu-pl-12{padding-left:var(--canon-space-12)}.md\:cu-pl-13{padding-left:var(--canon-space-13)}.md\:cu-pl-14{padding-left:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-pl{padding-left:var(--pl-lg)}.lg\:cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.lg\:cu-pl-1{padding-left:var(--canon-space-1)}.lg\:cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.lg\:cu-pl-2{padding-left:var(--canon-space-2)}.lg\:cu-pl-3{padding-left:var(--canon-space-3)}.lg\:cu-pl-4{padding-left:var(--canon-space-4)}.lg\:cu-pl-5{padding-left:var(--canon-space-5)}.lg\:cu-pl-6{padding-left:var(--canon-space-6)}.lg\:cu-pl-7{padding-left:var(--canon-space-7)}.lg\:cu-pl-8{padding-left:var(--canon-space-8)}.lg\:cu-pl-9{padding-left:var(--canon-space-9)}.lg\:cu-pl-10{padding-left:var(--canon-space-10)}.lg\:cu-pl-11{padding-left:var(--canon-space-11)}.lg\:cu-pl-12{padding-left:var(--canon-space-12)}.lg\:cu-pl-13{padding-left:var(--canon-space-13)}.lg\:cu-pl-14{padding-left:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-pl{padding-left:var(--pl-xl)}.xl\:cu-pl-0\.5{padding-left:var(--canon-space-0_5)}.xl\:cu-pl-1{padding-left:var(--canon-space-1)}.xl\:cu-pl-1\.5{padding-left:var(--canon-space-1_5)}.xl\:cu-pl-2{padding-left:var(--canon-space-2)}.xl\:cu-pl-3{padding-left:var(--canon-space-3)}.xl\:cu-pl-4{padding-left:var(--canon-space-4)}.xl\:cu-pl-5{padding-left:var(--canon-space-5)}.xl\:cu-pl-6{padding-left:var(--canon-space-6)}.xl\:cu-pl-7{padding-left:var(--canon-space-7)}.xl\:cu-pl-8{padding-left:var(--canon-space-8)}.xl\:cu-pl-9{padding-left:var(--canon-space-9)}.xl\:cu-pl-10{padding-left:var(--canon-space-10)}.xl\:cu-pl-11{padding-left:var(--canon-space-11)}.xl\:cu-pl-12{padding-left:var(--canon-space-12)}.xl\:cu-pl-13{padding-left:var(--canon-space-13)}.xl\:cu-pl-14{padding-left:var(--canon-space-14)}}.cu-pr{padding-right:var(--pr)}.cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.cu-pr-1{padding-right:var(--canon-space-1)}.cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.cu-pr-2{padding-right:var(--canon-space-2)}.cu-pr-3{padding-right:var(--canon-space-3)}.cu-pr-4{padding-right:var(--canon-space-4)}.cu-pr-5{padding-right:var(--canon-space-5)}.cu-pr-6{padding-right:var(--canon-space-6)}.cu-pr-7{padding-right:var(--canon-space-7)}.cu-pr-8{padding-right:var(--canon-space-8)}.cu-pr-9{padding-right:var(--canon-space-9)}.cu-pr-10{padding-right:var(--canon-space-10)}.cu-pr-11{padding-right:var(--canon-space-11)}.cu-pr-12{padding-right:var(--canon-space-12)}.cu-pr-13{padding-right:var(--canon-space-13)}.cu-pr-14{padding-right:var(--canon-space-14)}@media (width>=640px){.xs\:cu-pr{padding-right:var(--pr-xs)}.xs\:cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.xs\:cu-pr-1{padding-right:var(--canon-space-1)}.xs\:cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.xs\:cu-pr-2{padding-right:var(--canon-space-2)}.xs\:cu-pr-3{padding-right:var(--canon-space-3)}.xs\:cu-pr-4{padding-right:var(--canon-space-4)}.xs\:cu-pr-5{padding-right:var(--canon-space-5)}.xs\:cu-pr-6{padding-right:var(--canon-space-6)}.xs\:cu-pr-7{padding-right:var(--canon-space-7)}.xs\:cu-pr-8{padding-right:var(--canon-space-8)}.xs\:cu-pr-9{padding-right:var(--canon-space-9)}.xs\:cu-pr-10{padding-right:var(--canon-space-10)}.xs\:cu-pr-11{padding-right:var(--canon-space-11)}.xs\:cu-pr-12{padding-right:var(--canon-space-12)}.xs\:cu-pr-13{padding-right:var(--canon-space-13)}.xs\:cu-pr-14{padding-right:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-pr{padding-right:var(--pr-sm)}.sm\:cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.sm\:cu-pr-1{padding-right:var(--canon-space-1)}.sm\:cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.sm\:cu-pr-2{padding-right:var(--canon-space-2)}.sm\:cu-pr-3{padding-right:var(--canon-space-3)}.sm\:cu-pr-4{padding-right:var(--canon-space-4)}.sm\:cu-pr-5{padding-right:var(--canon-space-5)}.sm\:cu-pr-6{padding-right:var(--canon-space-6)}.sm\:cu-pr-7{padding-right:var(--canon-space-7)}.sm\:cu-pr-8{padding-right:var(--canon-space-8)}.sm\:cu-pr-9{padding-right:var(--canon-space-9)}.sm\:cu-pr-10{padding-right:var(--canon-space-10)}.sm\:cu-pr-11{padding-right:var(--canon-space-11)}.sm\:cu-pr-12{padding-right:var(--canon-space-12)}.sm\:cu-pr-13{padding-right:var(--canon-space-13)}.sm\:cu-pr-14{padding-right:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-pr{padding-right:var(--pr-md)}.md\:cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.md\:cu-pr-1{padding-right:var(--canon-space-1)}.md\:cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.md\:cu-pr-2{padding-right:var(--canon-space-2)}.md\:cu-pr-3{padding-right:var(--canon-space-3)}.md\:cu-pr-4{padding-right:var(--canon-space-4)}.md\:cu-pr-5{padding-right:var(--canon-space-5)}.md\:cu-pr-6{padding-right:var(--canon-space-6)}.md\:cu-pr-7{padding-right:var(--canon-space-7)}.md\:cu-pr-8{padding-right:var(--canon-space-8)}.md\:cu-pr-9{padding-right:var(--canon-space-9)}.md\:cu-pr-10{padding-right:var(--canon-space-10)}.md\:cu-pr-11{padding-right:var(--canon-space-11)}.md\:cu-pr-12{padding-right:var(--canon-space-12)}.md\:cu-pr-13{padding-right:var(--canon-space-13)}.md\:cu-pr-14{padding-right:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-pr{padding-right:var(--pr-lg)}.lg\:cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.lg\:cu-pr-1{padding-right:var(--canon-space-1)}.lg\:cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.lg\:cu-pr-2{padding-right:var(--canon-space-2)}.lg\:cu-pr-3{padding-right:var(--canon-space-3)}.lg\:cu-pr-4{padding-right:var(--canon-space-4)}.lg\:cu-pr-5{padding-right:var(--canon-space-5)}.lg\:cu-pr-6{padding-right:var(--canon-space-6)}.lg\:cu-pr-7{padding-right:var(--canon-space-7)}.lg\:cu-pr-8{padding-right:var(--canon-space-8)}.lg\:cu-pr-9{padding-right:var(--canon-space-9)}.lg\:cu-pr-10{padding-right:var(--canon-space-10)}.lg\:cu-pr-11{padding-right:var(--canon-space-11)}.lg\:cu-pr-12{padding-right:var(--canon-space-12)}.lg\:cu-pr-13{padding-right:var(--canon-space-13)}.lg\:cu-pr-14{padding-right:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-pr{padding-right:var(--pr-xl)}.xl\:cu-pr-0\.5{padding-right:var(--canon-space-0_5)}.xl\:cu-pr-1{padding-right:var(--canon-space-1)}.xl\:cu-pr-1\.5{padding-right:var(--canon-space-1_5)}.xl\:cu-pr-2{padding-right:var(--canon-space-2)}.xl\:cu-pr-3{padding-right:var(--canon-space-3)}.xl\:cu-pr-4{padding-right:var(--canon-space-4)}.xl\:cu-pr-5{padding-right:var(--canon-space-5)}.xl\:cu-pr-6{padding-right:var(--canon-space-6)}.xl\:cu-pr-7{padding-right:var(--canon-space-7)}.xl\:cu-pr-8{padding-right:var(--canon-space-8)}.xl\:cu-pr-9{padding-right:var(--canon-space-9)}.xl\:cu-pr-10{padding-right:var(--canon-space-10)}.xl\:cu-pr-11{padding-right:var(--canon-space-11)}.xl\:cu-pr-12{padding-right:var(--canon-space-12)}.xl\:cu-pr-13{padding-right:var(--canon-space-13)}.xl\:cu-pr-14{padding-right:var(--canon-space-14)}}.cu-pt{padding-top:var(--pt)}.cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.cu-pt-1{padding-top:var(--canon-space-1)}.cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.cu-pt-2{padding-top:var(--canon-space-2)}.cu-pt-3{padding-top:var(--canon-space-3)}.cu-pt-4{padding-top:var(--canon-space-4)}.cu-pt-5{padding-top:var(--canon-space-5)}.cu-pt-6{padding-top:var(--canon-space-6)}.cu-pt-7{padding-top:var(--canon-space-7)}.cu-pt-8{padding-top:var(--canon-space-8)}.cu-pt-9{padding-top:var(--canon-space-9)}.cu-pt-10{padding-top:var(--canon-space-10)}.cu-pt-11{padding-top:var(--canon-space-11)}.cu-pt-12{padding-top:var(--canon-space-12)}.cu-pt-13{padding-top:var(--canon-space-13)}.cu-pt-14{padding-top:var(--canon-space-14)}@media (width>=640px){.xs\:cu-pt{padding-top:var(--pt-xs)}.xs\:cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.xs\:cu-pt-1{padding-top:var(--canon-space-1)}.xs\:cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.xs\:cu-pt-2{padding-top:var(--canon-space-2)}.xs\:cu-pt-3{padding-top:var(--canon-space-3)}.xs\:cu-pt-4{padding-top:var(--canon-space-4)}.xs\:cu-pt-5{padding-top:var(--canon-space-5)}.xs\:cu-pt-6{padding-top:var(--canon-space-6)}.xs\:cu-pt-7{padding-top:var(--canon-space-7)}.xs\:cu-pt-8{padding-top:var(--canon-space-8)}.xs\:cu-pt-9{padding-top:var(--canon-space-9)}.xs\:cu-pt-10{padding-top:var(--canon-space-10)}.xs\:cu-pt-11{padding-top:var(--canon-space-11)}.xs\:cu-pt-12{padding-top:var(--canon-space-12)}.xs\:cu-pt-13{padding-top:var(--canon-space-13)}.xs\:cu-pt-14{padding-top:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-pt{padding-top:var(--pt-sm)}.sm\:cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.sm\:cu-pt-1{padding-top:var(--canon-space-1)}.sm\:cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.sm\:cu-pt-2{padding-top:var(--canon-space-2)}.sm\:cu-pt-3{padding-top:var(--canon-space-3)}.sm\:cu-pt-4{padding-top:var(--canon-space-4)}.sm\:cu-pt-5{padding-top:var(--canon-space-5)}.sm\:cu-pt-6{padding-top:var(--canon-space-6)}.sm\:cu-pt-7{padding-top:var(--canon-space-7)}.sm\:cu-pt-8{padding-top:var(--canon-space-8)}.sm\:cu-pt-9{padding-top:var(--canon-space-9)}.sm\:cu-pt-10{padding-top:var(--canon-space-10)}.sm\:cu-pt-11{padding-top:var(--canon-space-11)}.sm\:cu-pt-12{padding-top:var(--canon-space-12)}.sm\:cu-pt-13{padding-top:var(--canon-space-13)}.sm\:cu-pt-14{padding-top:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-pt{padding-top:var(--pt-md)}.md\:cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.md\:cu-pt-1{padding-top:var(--canon-space-1)}.md\:cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.md\:cu-pt-2{padding-top:var(--canon-space-2)}.md\:cu-pt-3{padding-top:var(--canon-space-3)}.md\:cu-pt-4{padding-top:var(--canon-space-4)}.md\:cu-pt-5{padding-top:var(--canon-space-5)}.md\:cu-pt-6{padding-top:var(--canon-space-6)}.md\:cu-pt-7{padding-top:var(--canon-space-7)}.md\:cu-pt-8{padding-top:var(--canon-space-8)}.md\:cu-pt-9{padding-top:var(--canon-space-9)}.md\:cu-pt-10{padding-top:var(--canon-space-10)}.md\:cu-pt-11{padding-top:var(--canon-space-11)}.md\:cu-pt-12{padding-top:var(--canon-space-12)}.md\:cu-pt-13{padding-top:var(--canon-space-13)}.md\:cu-pt-14{padding-top:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-pt{padding-top:var(--pt-lg)}.lg\:cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.lg\:cu-pt-1{padding-top:var(--canon-space-1)}.lg\:cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.lg\:cu-pt-2{padding-top:var(--canon-space-2)}.lg\:cu-pt-3{padding-top:var(--canon-space-3)}.lg\:cu-pt-4{padding-top:var(--canon-space-4)}.lg\:cu-pt-5{padding-top:var(--canon-space-5)}.lg\:cu-pt-6{padding-top:var(--canon-space-6)}.lg\:cu-pt-7{padding-top:var(--canon-space-7)}.lg\:cu-pt-8{padding-top:var(--canon-space-8)}.lg\:cu-pt-9{padding-top:var(--canon-space-9)}.lg\:cu-pt-10{padding-top:var(--canon-space-10)}.lg\:cu-pt-11{padding-top:var(--canon-space-11)}.lg\:cu-pt-12{padding-top:var(--canon-space-12)}.lg\:cu-pt-13{padding-top:var(--canon-space-13)}.lg\:cu-pt-14{padding-top:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-pt{padding-top:var(--pt-xl)}.xl\:cu-pt-0\.5{padding-top:var(--canon-space-0_5)}.xl\:cu-pt-1{padding-top:var(--canon-space-1)}.xl\:cu-pt-1\.5{padding-top:var(--canon-space-1_5)}.xl\:cu-pt-2{padding-top:var(--canon-space-2)}.xl\:cu-pt-3{padding-top:var(--canon-space-3)}.xl\:cu-pt-4{padding-top:var(--canon-space-4)}.xl\:cu-pt-5{padding-top:var(--canon-space-5)}.xl\:cu-pt-6{padding-top:var(--canon-space-6)}.xl\:cu-pt-7{padding-top:var(--canon-space-7)}.xl\:cu-pt-8{padding-top:var(--canon-space-8)}.xl\:cu-pt-9{padding-top:var(--canon-space-9)}.xl\:cu-pt-10{padding-top:var(--canon-space-10)}.xl\:cu-pt-11{padding-top:var(--canon-space-11)}.xl\:cu-pt-12{padding-top:var(--canon-space-12)}.xl\:cu-pt-13{padding-top:var(--canon-space-13)}.xl\:cu-pt-14{padding-top:var(--canon-space-14)}}.cu-pb{padding-bottom:var(--pb)}.cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.cu-pb-1{padding-bottom:var(--canon-space-1)}.cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.cu-pb-2{padding-bottom:var(--canon-space-2)}.cu-pb-3{padding-bottom:var(--canon-space-3)}.cu-pb-4{padding-bottom:var(--canon-space-4)}.cu-pb-5{padding-bottom:var(--canon-space-5)}.cu-pb-6{padding-bottom:var(--canon-space-6)}.cu-pb-7{padding-bottom:var(--canon-space-7)}.cu-pb-8{padding-bottom:var(--canon-space-8)}.cu-pb-9{padding-bottom:var(--canon-space-9)}.cu-pb-10{padding-bottom:var(--canon-space-10)}.cu-pb-11{padding-bottom:var(--canon-space-11)}.cu-pb-12{padding-bottom:var(--canon-space-12)}.cu-pb-13{padding-bottom:var(--canon-space-13)}.cu-pb-14{padding-bottom:var(--canon-space-14)}@media (width>=640px){.xs\:cu-pb{padding-bottom:var(--pb-xs)}.xs\:cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.xs\:cu-pb-1{padding-bottom:var(--canon-space-1)}.xs\:cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.xs\:cu-pb-2{padding-bottom:var(--canon-space-2)}.xs\:cu-pb-3{padding-bottom:var(--canon-space-3)}.xs\:cu-pb-4{padding-bottom:var(--canon-space-4)}.xs\:cu-pb-5{padding-bottom:var(--canon-space-5)}.xs\:cu-pb-6{padding-bottom:var(--canon-space-6)}.xs\:cu-pb-7{padding-bottom:var(--canon-space-7)}.xs\:cu-pb-8{padding-bottom:var(--canon-space-8)}.xs\:cu-pb-9{padding-bottom:var(--canon-space-9)}.xs\:cu-pb-10{padding-bottom:var(--canon-space-10)}.xs\:cu-pb-11{padding-bottom:var(--canon-space-11)}.xs\:cu-pb-12{padding-bottom:var(--canon-space-12)}.xs\:cu-pb-13{padding-bottom:var(--canon-space-13)}.xs\:cu-pb-14{padding-bottom:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-pb{padding-bottom:var(--pb-sm)}.sm\:cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.sm\:cu-pb-1{padding-bottom:var(--canon-space-1)}.sm\:cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.sm\:cu-pb-2{padding-bottom:var(--canon-space-2)}.sm\:cu-pb-3{padding-bottom:var(--canon-space-3)}.sm\:cu-pb-4{padding-bottom:var(--canon-space-4)}.sm\:cu-pb-5{padding-bottom:var(--canon-space-5)}.sm\:cu-pb-6{padding-bottom:var(--canon-space-6)}.sm\:cu-pb-7{padding-bottom:var(--canon-space-7)}.sm\:cu-pb-8{padding-bottom:var(--canon-space-8)}.sm\:cu-pb-9{padding-bottom:var(--canon-space-9)}.sm\:cu-pb-10{padding-bottom:var(--canon-space-10)}.sm\:cu-pb-11{padding-bottom:var(--canon-space-11)}.sm\:cu-pb-12{padding-bottom:var(--canon-space-12)}.sm\:cu-pb-13{padding-bottom:var(--canon-space-13)}.sm\:cu-pb-14{padding-bottom:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-pb{padding-bottom:var(--pb-md)}.md\:cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.md\:cu-pb-1{padding-bottom:var(--canon-space-1)}.md\:cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.md\:cu-pb-2{padding-bottom:var(--canon-space-2)}.md\:cu-pb-3{padding-bottom:var(--canon-space-3)}.md\:cu-pb-4{padding-bottom:var(--canon-space-4)}.md\:cu-pb-5{padding-bottom:var(--canon-space-5)}.md\:cu-pb-6{padding-bottom:var(--canon-space-6)}.md\:cu-pb-7{padding-bottom:var(--canon-space-7)}.md\:cu-pb-8{padding-bottom:var(--canon-space-8)}.md\:cu-pb-9{padding-bottom:var(--canon-space-9)}.md\:cu-pb-10{padding-bottom:var(--canon-space-10)}.md\:cu-pb-11{padding-bottom:var(--canon-space-11)}.md\:cu-pb-12{padding-bottom:var(--canon-space-12)}.md\:cu-pb-13{padding-bottom:var(--canon-space-13)}.md\:cu-pb-14{padding-bottom:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-pb{padding-bottom:var(--pb-lg)}.lg\:cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.lg\:cu-pb-1{padding-bottom:var(--canon-space-1)}.lg\:cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.lg\:cu-pb-2{padding-bottom:var(--canon-space-2)}.lg\:cu-pb-3{padding-bottom:var(--canon-space-3)}.lg\:cu-pb-4{padding-bottom:var(--canon-space-4)}.lg\:cu-pb-5{padding-bottom:var(--canon-space-5)}.lg\:cu-pb-6{padding-bottom:var(--canon-space-6)}.lg\:cu-pb-7{padding-bottom:var(--canon-space-7)}.lg\:cu-pb-8{padding-bottom:var(--canon-space-8)}.lg\:cu-pb-9{padding-bottom:var(--canon-space-9)}.lg\:cu-pb-10{padding-bottom:var(--canon-space-10)}.lg\:cu-pb-11{padding-bottom:var(--canon-space-11)}.lg\:cu-pb-12{padding-bottom:var(--canon-space-12)}.lg\:cu-pb-13{padding-bottom:var(--canon-space-13)}.lg\:cu-pb-14{padding-bottom:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-pb{padding-bottom:var(--pb-xl)}.xl\:cu-pb-0\.5{padding-bottom:var(--canon-space-0_5)}.xl\:cu-pb-1{padding-bottom:var(--canon-space-1)}.xl\:cu-pb-1\.5{padding-bottom:var(--canon-space-1_5)}.xl\:cu-pb-2{padding-bottom:var(--canon-space-2)}.xl\:cu-pb-3{padding-bottom:var(--canon-space-3)}.xl\:cu-pb-4{padding-bottom:var(--canon-space-4)}.xl\:cu-pb-5{padding-bottom:var(--canon-space-5)}.xl\:cu-pb-6{padding-bottom:var(--canon-space-6)}.xl\:cu-pb-7{padding-bottom:var(--canon-space-7)}.xl\:cu-pb-8{padding-bottom:var(--canon-space-8)}.xl\:cu-pb-9{padding-bottom:var(--canon-space-9)}.xl\:cu-pb-10{padding-bottom:var(--canon-space-10)}.xl\:cu-pb-11{padding-bottom:var(--canon-space-11)}.xl\:cu-pb-12{padding-bottom:var(--canon-space-12)}.xl\:cu-pb-13{padding-bottom:var(--canon-space-13)}.xl\:cu-pb-14{padding-bottom:var(--canon-space-14)}}.cu-py{padding-top:var(--py);padding-bottom:var(--py)}.cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}@media (width>=640px){.xs\:cu-py{padding-top:var(--py-xs);padding-bottom:var(--py-xs)}.xs\:cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.xs\:cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.xs\:cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.xs\:cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.xs\:cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.xs\:cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.xs\:cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.xs\:cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.xs\:cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.xs\:cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.xs\:cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.xs\:cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.xs\:cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.xs\:cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.xs\:cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.xs\:cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-py{padding-top:var(--py-sm);padding-bottom:var(--py-sm)}.sm\:cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.sm\:cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.sm\:cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.sm\:cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.sm\:cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.sm\:cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.sm\:cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.sm\:cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.sm\:cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.sm\:cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.sm\:cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.sm\:cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.sm\:cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.sm\:cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.sm\:cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.sm\:cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-py{padding-top:var(--py-md);padding-bottom:var(--py-md)}.md\:cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.md\:cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.md\:cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.md\:cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.md\:cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.md\:cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.md\:cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.md\:cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.md\:cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.md\:cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.md\:cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.md\:cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.md\:cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.md\:cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.md\:cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.md\:cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-py{padding-top:var(--py-lg);padding-bottom:var(--py-lg)}.lg\:cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.lg\:cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.lg\:cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.lg\:cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.lg\:cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.lg\:cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.lg\:cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.lg\:cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.lg\:cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.lg\:cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.lg\:cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.lg\:cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.lg\:cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.lg\:cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.lg\:cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.lg\:cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-py{padding-top:var(--py-xl);padding-bottom:var(--py-xl)}.xl\:cu-py-0\.5{padding-top:var(--canon-space-0_5);padding-bottom:var(--canon-space-0_5)}.xl\:cu-py-1{padding-top:var(--canon-space-1);padding-bottom:var(--canon-space-1)}.xl\:cu-py-1\.5{padding-top:var(--canon-space-1_5);padding-bottom:var(--canon-space-1_5)}.xl\:cu-py-2{padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-2)}.xl\:cu-py-3{padding-top:var(--canon-space-3);padding-bottom:var(--canon-space-3)}.xl\:cu-py-4{padding-top:var(--canon-space-4);padding-bottom:var(--canon-space-4)}.xl\:cu-py-5{padding-top:var(--canon-space-5);padding-bottom:var(--canon-space-5)}.xl\:cu-py-6{padding-top:var(--canon-space-6);padding-bottom:var(--canon-space-6)}.xl\:cu-py-7{padding-top:var(--canon-space-7);padding-bottom:var(--canon-space-7)}.xl\:cu-py-8{padding-top:var(--canon-space-8);padding-bottom:var(--canon-space-8)}.xl\:cu-py-9{padding-top:var(--canon-space-9);padding-bottom:var(--canon-space-9)}.xl\:cu-py-10{padding-top:var(--canon-space-10);padding-bottom:var(--canon-space-10)}.xl\:cu-py-11{padding-top:var(--canon-space-11);padding-bottom:var(--canon-space-11)}.xl\:cu-py-12{padding-top:var(--canon-space-12);padding-bottom:var(--canon-space-12)}.xl\:cu-py-13{padding-top:var(--canon-space-13);padding-bottom:var(--canon-space-13)}.xl\:cu-py-14{padding-top:var(--canon-space-14);padding-bottom:var(--canon-space-14)}}.cu-px{padding-left:var(--px);padding-right:var(--px)}.cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}@media (width>=640px){.xs\:cu-px{padding-left:var(--px-xs);padding-right:var(--px-xs)}.xs\:cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.xs\:cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.xs\:cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.xs\:cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.xs\:cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.xs\:cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.xs\:cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.xs\:cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.xs\:cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.xs\:cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.xs\:cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.xs\:cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.xs\:cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.xs\:cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.xs\:cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.xs\:cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-px{padding-left:var(--px-sm);padding-right:var(--px-sm)}.sm\:cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.sm\:cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.sm\:cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.sm\:cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.sm\:cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.sm\:cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.sm\:cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.sm\:cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.sm\:cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.sm\:cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.sm\:cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.sm\:cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.sm\:cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.sm\:cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.sm\:cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.sm\:cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-px{padding-left:var(--px-md);padding-right:var(--px-md)}.md\:cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.md\:cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.md\:cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.md\:cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.md\:cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.md\:cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.md\:cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.md\:cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.md\:cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.md\:cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.md\:cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.md\:cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.md\:cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.md\:cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.md\:cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.md\:cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-px{padding-left:var(--px-lg);padding-right:var(--px-lg)}.lg\:cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.lg\:cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.lg\:cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.lg\:cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.lg\:cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.lg\:cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.lg\:cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.lg\:cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.lg\:cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.lg\:cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.lg\:cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.lg\:cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.lg\:cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.lg\:cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.lg\:cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.lg\:cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-px{padding-left:var(--px-xl);padding-right:var(--px-xl)}.xl\:cu-px-0\.5{padding-left:var(--canon-space-0_5);padding-right:var(--canon-space-0_5)}.xl\:cu-px-1{padding-left:var(--canon-space-1);padding-right:var(--canon-space-1)}.xl\:cu-px-1\.5{padding-left:var(--canon-space-1_5);padding-right:var(--canon-space-1_5)}.xl\:cu-px-2{padding-left:var(--canon-space-2);padding-right:var(--canon-space-2)}.xl\:cu-px-3{padding-left:var(--canon-space-3);padding-right:var(--canon-space-3)}.xl\:cu-px-4{padding-left:var(--canon-space-4);padding-right:var(--canon-space-4)}.xl\:cu-px-5{padding-left:var(--canon-space-5);padding-right:var(--canon-space-5)}.xl\:cu-px-6{padding-left:var(--canon-space-6);padding-right:var(--canon-space-6)}.xl\:cu-px-7{padding-left:var(--canon-space-7);padding-right:var(--canon-space-7)}.xl\:cu-px-8{padding-left:var(--canon-space-8);padding-right:var(--canon-space-8)}.xl\:cu-px-9{padding-left:var(--canon-space-9);padding-right:var(--canon-space-9)}.xl\:cu-px-10{padding-left:var(--canon-space-10);padding-right:var(--canon-space-10)}.xl\:cu-px-11{padding-left:var(--canon-space-11);padding-right:var(--canon-space-11)}.xl\:cu-px-12{padding-left:var(--canon-space-12);padding-right:var(--canon-space-12)}.xl\:cu-px-13{padding-left:var(--canon-space-13);padding-right:var(--canon-space-13)}.xl\:cu-px-14{padding-left:var(--canon-space-14);padding-right:var(--canon-space-14)}}.cu-m{margin:var(--m)}.cu-m-0\.5{margin:var(--canon-space-0_5)}.cu-m-1{margin:var(--canon-space-1)}.cu-m-1\.5{margin:var(--canon-space-1_5)}.cu-m-2{margin:var(--canon-space-2)}.cu-m-3{margin:var(--canon-space-3)}.cu-m-4{margin:var(--canon-space-4)}.cu-m-5{margin:var(--canon-space-5)}.cu-m-6{margin:var(--canon-space-6)}.cu-m-7{margin:var(--canon-space-7)}.cu-m-8{margin:var(--canon-space-8)}.cu-m-9{margin:var(--canon-space-9)}.cu-m-10{margin:var(--canon-space-10)}.cu-m-11{margin:var(--canon-space-11)}.cu-m-12{margin:var(--canon-space-12)}.cu-m-13{margin:var(--canon-space-13)}.cu-m-14{margin:var(--canon-space-14)}@media (width>=640px){.xs\:cu-m{margin:var(--p-xs)}.xs\:cu-m-0\.5{margin:var(--canon-space-0_5)}.xs\:cu-m-1{margin:var(--canon-space-1)}.xs\:cu-m-1\.5{margin:var(--canon-space-1_5)}.xs\:cu-m-2{margin:var(--canon-space-2)}.xs\:cu-m-3{margin:var(--canon-space-3)}.xs\:cu-m-4{margin:var(--canon-space-4)}.xs\:cu-m-5{margin:var(--canon-space-5)}.xs\:cu-m-6{margin:var(--canon-space-6)}.xs\:cu-m-7{margin:var(--canon-space-7)}.xs\:cu-m-8{margin:var(--canon-space-8)}.xs\:cu-m-9{margin:var(--canon-space-9)}.xs\:cu-m-10{margin:var(--canon-space-10)}.xs\:cu-m-11{margin:var(--canon-space-11)}.xs\:cu-m-12{margin:var(--canon-space-12)}.xs\:cu-m-13{margin:var(--canon-space-13)}.xs\:cu-m-14{margin:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-m{margin:var(--p-sm)}.sm\:cu-m-0\.5{margin:var(--canon-space-0_5)}.sm\:cu-m-1{margin:var(--canon-space-1)}.sm\:cu-m-1\.5{margin:var(--canon-space-1_5)}.sm\:cu-m-2{margin:var(--canon-space-2)}.sm\:cu-m-3{margin:var(--canon-space-3)}.sm\:cu-m-4{margin:var(--canon-space-4)}.sm\:cu-m-5{margin:var(--canon-space-5)}.sm\:cu-m-6{margin:var(--canon-space-6)}.sm\:cu-m-7{margin:var(--canon-space-7)}.sm\:cu-m-8{margin:var(--canon-space-8)}.sm\:cu-m-9{margin:var(--canon-space-9)}.sm\:cu-m-10{margin:var(--canon-space-10)}.sm\:cu-m-11{margin:var(--canon-space-11)}.sm\:cu-m-12{margin:var(--canon-space-12)}.sm\:cu-m-13{margin:var(--canon-space-13)}.sm\:cu-m-14{margin:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-m{margin:var(--p-md)}.md\:cu-m-0\.5{margin:var(--canon-space-0_5)}.md\:cu-m-1{margin:var(--canon-space-1)}.md\:cu-m-1\.5{margin:var(--canon-space-1_5)}.md\:cu-m-2{margin:var(--canon-space-2)}.md\:cu-m-3{margin:var(--canon-space-3)}.md\:cu-m-4{margin:var(--canon-space-4)}.md\:cu-m-5{margin:var(--canon-space-5)}.md\:cu-m-6{margin:var(--canon-space-6)}.md\:cu-m-7{margin:var(--canon-space-7)}.md\:cu-m-8{margin:var(--canon-space-8)}.md\:cu-m-9{margin:var(--canon-space-9)}.md\:cu-m-10{margin:var(--canon-space-10)}.md\:cu-m-11{margin:var(--canon-space-11)}.md\:cu-m-12{margin:var(--canon-space-12)}.md\:cu-m-13{margin:var(--canon-space-13)}.md\:cu-m-14{margin:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-m{margin:var(--p-lg)}.lg\:cu-m-0\.5{margin:var(--canon-space-0_5)}.lg\:cu-m-1{margin:var(--canon-space-1)}.lg\:cu-m-1\.5{margin:var(--canon-space-1_5)}.lg\:cu-m-2{margin:var(--canon-space-2)}.lg\:cu-m-3{margin:var(--canon-space-3)}.lg\:cu-m-4{margin:var(--canon-space-4)}.lg\:cu-m-5{margin:var(--canon-space-5)}.lg\:cu-m-6{margin:var(--canon-space-6)}.lg\:cu-m-7{margin:var(--canon-space-7)}.lg\:cu-m-8{margin:var(--canon-space-8)}.lg\:cu-m-9{margin:var(--canon-space-9)}.lg\:cu-m-10{margin:var(--canon-space-10)}.lg\:cu-m-11{margin:var(--canon-space-11)}.lg\:cu-m-12{margin:var(--canon-space-12)}.lg\:cu-m-13{margin:var(--canon-space-13)}.lg\:cu-m-14{margin:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-m{margin:var(--p-xl)}.xl\:cu-m-0\.5{margin:var(--canon-space-0_5)}.xl\:cu-m-1{margin:var(--canon-space-1)}.xl\:cu-m-1\.5{margin:var(--canon-space-1_5)}.xl\:cu-m-2{margin:var(--canon-space-2)}.xl\:cu-m-3{margin:var(--canon-space-3)}.xl\:cu-m-4{margin:var(--canon-space-4)}.xl\:cu-m-5{margin:var(--canon-space-5)}.xl\:cu-m-6{margin:var(--canon-space-6)}.xl\:cu-m-7{margin:var(--canon-space-7)}.xl\:cu-m-8{margin:var(--canon-space-8)}.xl\:cu-m-9{margin:var(--canon-space-9)}.xl\:cu-m-10{margin:var(--canon-space-10)}.xl\:cu-m-11{margin:var(--canon-space-11)}.xl\:cu-m-12{margin:var(--canon-space-12)}.xl\:cu-m-13{margin:var(--canon-space-13)}.xl\:cu-m-14{margin:var(--canon-space-14)}}.cu-ml{margin-left:var(--ml)}.cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.cu-ml-1{margin-left:var(--canon-space-1)}.cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.cu-ml-2{margin-left:var(--canon-space-2)}.cu-ml-3{margin-left:var(--canon-space-3)}.cu-ml-4{margin-left:var(--canon-space-4)}.cu-ml-5{margin-left:var(--canon-space-5)}.cu-ml-6{margin-left:var(--canon-space-6)}.cu-ml-7{margin-left:var(--canon-space-7)}.cu-ml-8{margin-left:var(--canon-space-8)}.cu-ml-9{margin-left:var(--canon-space-9)}.cu-ml-10{margin-left:var(--canon-space-10)}.cu-ml-11{margin-left:var(--canon-space-11)}.cu-ml-12{margin-left:var(--canon-space-12)}.cu-ml-13{margin-left:var(--canon-space-13)}.cu-ml-14{margin-left:var(--canon-space-14)}@media (width>=640px){.xs\:cu-ml{margin-left:var(--pl-xs)}.xs\:cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.xs\:cu-ml-1{margin-left:var(--canon-space-1)}.xs\:cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.xs\:cu-ml-2{margin-left:var(--canon-space-2)}.xs\:cu-ml-3{margin-left:var(--canon-space-3)}.xs\:cu-ml-4{margin-left:var(--canon-space-4)}.xs\:cu-ml-5{margin-left:var(--canon-space-5)}.xs\:cu-ml-6{margin-left:var(--canon-space-6)}.xs\:cu-ml-7{margin-left:var(--canon-space-7)}.xs\:cu-ml-8{margin-left:var(--canon-space-8)}.xs\:cu-ml-9{margin-left:var(--canon-space-9)}.xs\:cu-ml-10{margin-left:var(--canon-space-10)}.xs\:cu-ml-11{margin-left:var(--canon-space-11)}.xs\:cu-ml-12{margin-left:var(--canon-space-12)}.xs\:cu-ml-13{margin-left:var(--canon-space-13)}.xs\:cu-ml-14{margin-left:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-ml{margin-left:var(--pl-sm)}.sm\:cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.sm\:cu-ml-1{margin-left:var(--canon-space-1)}.sm\:cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.sm\:cu-ml-2{margin-left:var(--canon-space-2)}.sm\:cu-ml-3{margin-left:var(--canon-space-3)}.sm\:cu-ml-4{margin-left:var(--canon-space-4)}.sm\:cu-ml-5{margin-left:var(--canon-space-5)}.sm\:cu-ml-6{margin-left:var(--canon-space-6)}.sm\:cu-ml-7{margin-left:var(--canon-space-7)}.sm\:cu-ml-8{margin-left:var(--canon-space-8)}.sm\:cu-ml-9{margin-left:var(--canon-space-9)}.sm\:cu-ml-10{margin-left:var(--canon-space-10)}.sm\:cu-ml-11{margin-left:var(--canon-space-11)}.sm\:cu-ml-12{margin-left:var(--canon-space-12)}.sm\:cu-ml-13{margin-left:var(--canon-space-13)}.sm\:cu-ml-14{margin-left:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-ml{margin-left:var(--pl-md)}.md\:cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.md\:cu-ml-1{margin-left:var(--canon-space-1)}.md\:cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.md\:cu-ml-2{margin-left:var(--canon-space-2)}.md\:cu-ml-3{margin-left:var(--canon-space-3)}.md\:cu-ml-4{margin-left:var(--canon-space-4)}.md\:cu-ml-5{margin-left:var(--canon-space-5)}.md\:cu-ml-6{margin-left:var(--canon-space-6)}.md\:cu-ml-7{margin-left:var(--canon-space-7)}.md\:cu-ml-8{margin-left:var(--canon-space-8)}.md\:cu-ml-9{margin-left:var(--canon-space-9)}.md\:cu-ml-10{margin-left:var(--canon-space-10)}.md\:cu-ml-11{margin-left:var(--canon-space-11)}.md\:cu-ml-12{margin-left:var(--canon-space-12)}.md\:cu-ml-13{margin-left:var(--canon-space-13)}.md\:cu-ml-14{margin-left:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-ml{margin-left:var(--pl-lg)}.lg\:cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.lg\:cu-ml-1{margin-left:var(--canon-space-1)}.lg\:cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.lg\:cu-ml-2{margin-left:var(--canon-space-2)}.lg\:cu-ml-3{margin-left:var(--canon-space-3)}.lg\:cu-ml-4{margin-left:var(--canon-space-4)}.lg\:cu-ml-5{margin-left:var(--canon-space-5)}.lg\:cu-ml-6{margin-left:var(--canon-space-6)}.lg\:cu-ml-7{margin-left:var(--canon-space-7)}.lg\:cu-ml-8{margin-left:var(--canon-space-8)}.lg\:cu-ml-9{margin-left:var(--canon-space-9)}.lg\:cu-ml-10{margin-left:var(--canon-space-10)}.lg\:cu-ml-11{margin-left:var(--canon-space-11)}.lg\:cu-ml-12{margin-left:var(--canon-space-12)}.lg\:cu-ml-13{margin-left:var(--canon-space-13)}.lg\:cu-ml-14{margin-left:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-ml{margin-left:var(--pl-xl)}.xl\:cu-ml-0\.5{margin-left:var(--canon-space-0_5)}.xl\:cu-ml-1{margin-left:var(--canon-space-1)}.xl\:cu-ml-1\.5{margin-left:var(--canon-space-1_5)}.xl\:cu-ml-2{margin-left:var(--canon-space-2)}.xl\:cu-ml-3{margin-left:var(--canon-space-3)}.xl\:cu-ml-4{margin-left:var(--canon-space-4)}.xl\:cu-ml-5{margin-left:var(--canon-space-5)}.xl\:cu-ml-6{margin-left:var(--canon-space-6)}.xl\:cu-ml-7{margin-left:var(--canon-space-7)}.xl\:cu-ml-8{margin-left:var(--canon-space-8)}.xl\:cu-ml-9{margin-left:var(--canon-space-9)}.xl\:cu-ml-10{margin-left:var(--canon-space-10)}.xl\:cu-ml-11{margin-left:var(--canon-space-11)}.xl\:cu-ml-12{margin-left:var(--canon-space-12)}.xl\:cu-ml-13{margin-left:var(--canon-space-13)}.xl\:cu-ml-14{margin-left:var(--canon-space-14)}}.cu-mr{margin-right:var(--mr)}.cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.cu-mr-1{margin-right:var(--canon-space-1)}.cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.cu-mr-2{margin-right:var(--canon-space-2)}.cu-mr-3{margin-right:var(--canon-space-3)}.cu-mr-4{margin-right:var(--canon-space-4)}.cu-mr-5{margin-right:var(--canon-space-5)}.cu-mr-6{margin-right:var(--canon-space-6)}.cu-mr-7{margin-right:var(--canon-space-7)}.cu-mr-8{margin-right:var(--canon-space-8)}.cu-mr-9{margin-right:var(--canon-space-9)}.cu-mr-10{margin-right:var(--canon-space-10)}.cu-mr-11{margin-right:var(--canon-space-11)}.cu-mr-12{margin-right:var(--canon-space-12)}.cu-mr-13{margin-right:var(--canon-space-13)}.cu-mr-14{margin-right:var(--canon-space-14)}@media (width>=640px){.xs\:cu-mr{margin-right:var(--pr-xs)}.xs\:cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.xs\:cu-mr-1{margin-right:var(--canon-space-1)}.xs\:cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.xs\:cu-mr-2{margin-right:var(--canon-space-2)}.xs\:cu-mr-3{margin-right:var(--canon-space-3)}.xs\:cu-mr-4{margin-right:var(--canon-space-4)}.xs\:cu-mr-5{margin-right:var(--canon-space-5)}.xs\:cu-mr-6{margin-right:var(--canon-space-6)}.xs\:cu-mr-7{margin-right:var(--canon-space-7)}.xs\:cu-mr-8{margin-right:var(--canon-space-8)}.xs\:cu-mr-9{margin-right:var(--canon-space-9)}.xs\:cu-mr-10{margin-right:var(--canon-space-10)}.xs\:cu-mr-11{margin-right:var(--canon-space-11)}.xs\:cu-mr-12{margin-right:var(--canon-space-12)}.xs\:cu-mr-13{margin-right:var(--canon-space-13)}.xs\:cu-mr-14{margin-right:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-mr{margin-right:var(--pr-sm)}.sm\:cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.sm\:cu-mr-1{margin-right:var(--canon-space-1)}.sm\:cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.sm\:cu-mr-2{margin-right:var(--canon-space-2)}.sm\:cu-mr-3{margin-right:var(--canon-space-3)}.sm\:cu-mr-4{margin-right:var(--canon-space-4)}.sm\:cu-mr-5{margin-right:var(--canon-space-5)}.sm\:cu-mr-6{margin-right:var(--canon-space-6)}.sm\:cu-mr-7{margin-right:var(--canon-space-7)}.sm\:cu-mr-8{margin-right:var(--canon-space-8)}.sm\:cu-mr-9{margin-right:var(--canon-space-9)}.sm\:cu-mr-10{margin-right:var(--canon-space-10)}.sm\:cu-mr-11{margin-right:var(--canon-space-11)}.sm\:cu-mr-12{margin-right:var(--canon-space-12)}.sm\:cu-mr-13{margin-right:var(--canon-space-13)}.sm\:cu-mr-14{margin-right:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-mr{margin-right:var(--pr-md)}.md\:cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.md\:cu-mr-1{margin-right:var(--canon-space-1)}.md\:cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.md\:cu-mr-2{margin-right:var(--canon-space-2)}.md\:cu-mr-3{margin-right:var(--canon-space-3)}.md\:cu-mr-4{margin-right:var(--canon-space-4)}.md\:cu-mr-5{margin-right:var(--canon-space-5)}.md\:cu-mr-6{margin-right:var(--canon-space-6)}.md\:cu-mr-7{margin-right:var(--canon-space-7)}.md\:cu-mr-8{margin-right:var(--canon-space-8)}.md\:cu-mr-9{margin-right:var(--canon-space-9)}.md\:cu-mr-10{margin-right:var(--canon-space-10)}.md\:cu-mr-11{margin-right:var(--canon-space-11)}.md\:cu-mr-12{margin-right:var(--canon-space-12)}.md\:cu-mr-13{margin-right:var(--canon-space-13)}.md\:cu-mr-14{margin-right:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-mr{margin-right:var(--pr-lg)}.lg\:cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.lg\:cu-mr-1{margin-right:var(--canon-space-1)}.lg\:cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.lg\:cu-mr-2{margin-right:var(--canon-space-2)}.lg\:cu-mr-3{margin-right:var(--canon-space-3)}.lg\:cu-mr-4{margin-right:var(--canon-space-4)}.lg\:cu-mr-5{margin-right:var(--canon-space-5)}.lg\:cu-mr-6{margin-right:var(--canon-space-6)}.lg\:cu-mr-7{margin-right:var(--canon-space-7)}.lg\:cu-mr-8{margin-right:var(--canon-space-8)}.lg\:cu-mr-9{margin-right:var(--canon-space-9)}.lg\:cu-mr-10{margin-right:var(--canon-space-10)}.lg\:cu-mr-11{margin-right:var(--canon-space-11)}.lg\:cu-mr-12{margin-right:var(--canon-space-12)}.lg\:cu-mr-13{margin-right:var(--canon-space-13)}.lg\:cu-mr-14{margin-right:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-mr{margin-right:var(--pr-xl)}.xl\:cu-mr-0\.5{margin-right:var(--canon-space-0_5)}.xl\:cu-mr-1{margin-right:var(--canon-space-1)}.xl\:cu-mr-1\.5{margin-right:var(--canon-space-1_5)}.xl\:cu-mr-2{margin-right:var(--canon-space-2)}.xl\:cu-mr-3{margin-right:var(--canon-space-3)}.xl\:cu-mr-4{margin-right:var(--canon-space-4)}.xl\:cu-mr-5{margin-right:var(--canon-space-5)}.xl\:cu-mr-6{margin-right:var(--canon-space-6)}.xl\:cu-mr-7{margin-right:var(--canon-space-7)}.xl\:cu-mr-8{margin-right:var(--canon-space-8)}.xl\:cu-mr-9{margin-right:var(--canon-space-9)}.xl\:cu-mr-10{margin-right:var(--canon-space-10)}.xl\:cu-mr-11{margin-right:var(--canon-space-11)}.xl\:cu-mr-12{margin-right:var(--canon-space-12)}.xl\:cu-mr-13{margin-right:var(--canon-space-13)}.xl\:cu-mr-14{margin-right:var(--canon-space-14)}}.cu-mt{margin-top:var(--mt)}.cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.cu-mt-1{margin-top:var(--canon-space-1)}.cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.cu-mt-2{margin-top:var(--canon-space-2)}.cu-mt-3{margin-top:var(--canon-space-3)}.cu-mt-4{margin-top:var(--canon-space-4)}.cu-mt-5{margin-top:var(--canon-space-5)}.cu-mt-6{margin-top:var(--canon-space-6)}.cu-mt-7{margin-top:var(--canon-space-7)}.cu-mt-8{margin-top:var(--canon-space-8)}.cu-mt-9{margin-top:var(--canon-space-9)}.cu-mt-10{margin-top:var(--canon-space-10)}.cu-mt-11{margin-top:var(--canon-space-11)}.cu-mt-12{margin-top:var(--canon-space-12)}.cu-mt-13{margin-top:var(--canon-space-13)}.cu-mt-14{margin-top:var(--canon-space-14)}@media (width>=640px){.xs\:cu-mt{margin-top:var(--pt-xs)}.xs\:cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.xs\:cu-mt-1{margin-top:var(--canon-space-1)}.xs\:cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.xs\:cu-mt-2{margin-top:var(--canon-space-2)}.xs\:cu-mt-3{margin-top:var(--canon-space-3)}.xs\:cu-mt-4{margin-top:var(--canon-space-4)}.xs\:cu-mt-5{margin-top:var(--canon-space-5)}.xs\:cu-mt-6{margin-top:var(--canon-space-6)}.xs\:cu-mt-7{margin-top:var(--canon-space-7)}.xs\:cu-mt-8{margin-top:var(--canon-space-8)}.xs\:cu-mt-9{margin-top:var(--canon-space-9)}.xs\:cu-mt-10{margin-top:var(--canon-space-10)}.xs\:cu-mt-11{margin-top:var(--canon-space-11)}.xs\:cu-mt-12{margin-top:var(--canon-space-12)}.xs\:cu-mt-13{margin-top:var(--canon-space-13)}.xs\:cu-mt-14{margin-top:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-mt{margin-top:var(--pt-sm)}.sm\:cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.sm\:cu-mt-1{margin-top:var(--canon-space-1)}.sm\:cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.sm\:cu-mt-2{margin-top:var(--canon-space-2)}.sm\:cu-mt-3{margin-top:var(--canon-space-3)}.sm\:cu-mt-4{margin-top:var(--canon-space-4)}.sm\:cu-mt-5{margin-top:var(--canon-space-5)}.sm\:cu-mt-6{margin-top:var(--canon-space-6)}.sm\:cu-mt-7{margin-top:var(--canon-space-7)}.sm\:cu-mt-8{margin-top:var(--canon-space-8)}.sm\:cu-mt-9{margin-top:var(--canon-space-9)}.sm\:cu-mt-10{margin-top:var(--canon-space-10)}.sm\:cu-mt-11{margin-top:var(--canon-space-11)}.sm\:cu-mt-12{margin-top:var(--canon-space-12)}.sm\:cu-mt-13{margin-top:var(--canon-space-13)}.sm\:cu-mt-14{margin-top:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-mt{margin-top:var(--pt-md)}.md\:cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.md\:cu-mt-1{margin-top:var(--canon-space-1)}.md\:cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.md\:cu-mt-2{margin-top:var(--canon-space-2)}.md\:cu-mt-3{margin-top:var(--canon-space-3)}.md\:cu-mt-4{margin-top:var(--canon-space-4)}.md\:cu-mt-5{margin-top:var(--canon-space-5)}.md\:cu-mt-6{margin-top:var(--canon-space-6)}.md\:cu-mt-7{margin-top:var(--canon-space-7)}.md\:cu-mt-8{margin-top:var(--canon-space-8)}.md\:cu-mt-9{margin-top:var(--canon-space-9)}.md\:cu-mt-10{margin-top:var(--canon-space-10)}.md\:cu-mt-11{margin-top:var(--canon-space-11)}.md\:cu-mt-12{margin-top:var(--canon-space-12)}.md\:cu-mt-13{margin-top:var(--canon-space-13)}.md\:cu-mt-14{margin-top:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-mt{margin-top:var(--pt-lg)}.lg\:cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.lg\:cu-mt-1{margin-top:var(--canon-space-1)}.lg\:cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.lg\:cu-mt-2{margin-top:var(--canon-space-2)}.lg\:cu-mt-3{margin-top:var(--canon-space-3)}.lg\:cu-mt-4{margin-top:var(--canon-space-4)}.lg\:cu-mt-5{margin-top:var(--canon-space-5)}.lg\:cu-mt-6{margin-top:var(--canon-space-6)}.lg\:cu-mt-7{margin-top:var(--canon-space-7)}.lg\:cu-mt-8{margin-top:var(--canon-space-8)}.lg\:cu-mt-9{margin-top:var(--canon-space-9)}.lg\:cu-mt-10{margin-top:var(--canon-space-10)}.lg\:cu-mt-11{margin-top:var(--canon-space-11)}.lg\:cu-mt-12{margin-top:var(--canon-space-12)}.lg\:cu-mt-13{margin-top:var(--canon-space-13)}.lg\:cu-mt-14{margin-top:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-mt{margin-top:var(--pt-xl)}.xl\:cu-mt-0\.5{margin-top:var(--canon-space-0_5)}.xl\:cu-mt-1{margin-top:var(--canon-space-1)}.xl\:cu-mt-1\.5{margin-top:var(--canon-space-1_5)}.xl\:cu-mt-2{margin-top:var(--canon-space-2)}.xl\:cu-mt-3{margin-top:var(--canon-space-3)}.xl\:cu-mt-4{margin-top:var(--canon-space-4)}.xl\:cu-mt-5{margin-top:var(--canon-space-5)}.xl\:cu-mt-6{margin-top:var(--canon-space-6)}.xl\:cu-mt-7{margin-top:var(--canon-space-7)}.xl\:cu-mt-8{margin-top:var(--canon-space-8)}.xl\:cu-mt-9{margin-top:var(--canon-space-9)}.xl\:cu-mt-10{margin-top:var(--canon-space-10)}.xl\:cu-mt-11{margin-top:var(--canon-space-11)}.xl\:cu-mt-12{margin-top:var(--canon-space-12)}.xl\:cu-mt-13{margin-top:var(--canon-space-13)}.xl\:cu-mt-14{margin-top:var(--canon-space-14)}}.cu-mb{margin-bottom:var(--mb)}.cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.cu-mb-1{margin-bottom:var(--canon-space-1)}.cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.cu-mb-2{margin-bottom:var(--canon-space-2)}.cu-mb-3{margin-bottom:var(--canon-space-3)}.cu-mb-4{margin-bottom:var(--canon-space-4)}.cu-mb-5{margin-bottom:var(--canon-space-5)}.cu-mb-6{margin-bottom:var(--canon-space-6)}.cu-mb-7{margin-bottom:var(--canon-space-7)}.cu-mb-8{margin-bottom:var(--canon-space-8)}.cu-mb-9{margin-bottom:var(--canon-space-9)}.cu-mb-10{margin-bottom:var(--canon-space-10)}.cu-mb-11{margin-bottom:var(--canon-space-11)}.cu-mb-12{margin-bottom:var(--canon-space-12)}.cu-mb-13{margin-bottom:var(--canon-space-13)}.cu-mb-14{margin-bottom:var(--canon-space-14)}@media (width>=640px){.xs\:cu-mb{margin-bottom:var(--pb-xs)}.xs\:cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.xs\:cu-mb-1{margin-bottom:var(--canon-space-1)}.xs\:cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.xs\:cu-mb-2{margin-bottom:var(--canon-space-2)}.xs\:cu-mb-3{margin-bottom:var(--canon-space-3)}.xs\:cu-mb-4{margin-bottom:var(--canon-space-4)}.xs\:cu-mb-5{margin-bottom:var(--canon-space-5)}.xs\:cu-mb-6{margin-bottom:var(--canon-space-6)}.xs\:cu-mb-7{margin-bottom:var(--canon-space-7)}.xs\:cu-mb-8{margin-bottom:var(--canon-space-8)}.xs\:cu-mb-9{margin-bottom:var(--canon-space-9)}.xs\:cu-mb-10{margin-bottom:var(--canon-space-10)}.xs\:cu-mb-11{margin-bottom:var(--canon-space-11)}.xs\:cu-mb-12{margin-bottom:var(--canon-space-12)}.xs\:cu-mb-13{margin-bottom:var(--canon-space-13)}.xs\:cu-mb-14{margin-bottom:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-mb{margin-bottom:var(--pb-sm)}.sm\:cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.sm\:cu-mb-1{margin-bottom:var(--canon-space-1)}.sm\:cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.sm\:cu-mb-2{margin-bottom:var(--canon-space-2)}.sm\:cu-mb-3{margin-bottom:var(--canon-space-3)}.sm\:cu-mb-4{margin-bottom:var(--canon-space-4)}.sm\:cu-mb-5{margin-bottom:var(--canon-space-5)}.sm\:cu-mb-6{margin-bottom:var(--canon-space-6)}.sm\:cu-mb-7{margin-bottom:var(--canon-space-7)}.sm\:cu-mb-8{margin-bottom:var(--canon-space-8)}.sm\:cu-mb-9{margin-bottom:var(--canon-space-9)}.sm\:cu-mb-10{margin-bottom:var(--canon-space-10)}.sm\:cu-mb-11{margin-bottom:var(--canon-space-11)}.sm\:cu-mb-12{margin-bottom:var(--canon-space-12)}.sm\:cu-mb-13{margin-bottom:var(--canon-space-13)}.sm\:cu-mb-14{margin-bottom:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-mb{margin-bottom:var(--pb-md)}.md\:cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.md\:cu-mb-1{margin-bottom:var(--canon-space-1)}.md\:cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.md\:cu-mb-2{margin-bottom:var(--canon-space-2)}.md\:cu-mb-3{margin-bottom:var(--canon-space-3)}.md\:cu-mb-4{margin-bottom:var(--canon-space-4)}.md\:cu-mb-5{margin-bottom:var(--canon-space-5)}.md\:cu-mb-6{margin-bottom:var(--canon-space-6)}.md\:cu-mb-7{margin-bottom:var(--canon-space-7)}.md\:cu-mb-8{margin-bottom:var(--canon-space-8)}.md\:cu-mb-9{margin-bottom:var(--canon-space-9)}.md\:cu-mb-10{margin-bottom:var(--canon-space-10)}.md\:cu-mb-11{margin-bottom:var(--canon-space-11)}.md\:cu-mb-12{margin-bottom:var(--canon-space-12)}.md\:cu-mb-13{margin-bottom:var(--canon-space-13)}.md\:cu-mb-14{margin-bottom:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-mb{margin-bottom:var(--pb-lg)}.lg\:cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.lg\:cu-mb-1{margin-bottom:var(--canon-space-1)}.lg\:cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.lg\:cu-mb-2{margin-bottom:var(--canon-space-2)}.lg\:cu-mb-3{margin-bottom:var(--canon-space-3)}.lg\:cu-mb-4{margin-bottom:var(--canon-space-4)}.lg\:cu-mb-5{margin-bottom:var(--canon-space-5)}.lg\:cu-mb-6{margin-bottom:var(--canon-space-6)}.lg\:cu-mb-7{margin-bottom:var(--canon-space-7)}.lg\:cu-mb-8{margin-bottom:var(--canon-space-8)}.lg\:cu-mb-9{margin-bottom:var(--canon-space-9)}.lg\:cu-mb-10{margin-bottom:var(--canon-space-10)}.lg\:cu-mb-11{margin-bottom:var(--canon-space-11)}.lg\:cu-mb-12{margin-bottom:var(--canon-space-12)}.lg\:cu-mb-13{margin-bottom:var(--canon-space-13)}.lg\:cu-mb-14{margin-bottom:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-mb{margin-bottom:var(--pb-xl)}.xl\:cu-mb-0\.5{margin-bottom:var(--canon-space-0_5)}.xl\:cu-mb-1{margin-bottom:var(--canon-space-1)}.xl\:cu-mb-1\.5{margin-bottom:var(--canon-space-1_5)}.xl\:cu-mb-2{margin-bottom:var(--canon-space-2)}.xl\:cu-mb-3{margin-bottom:var(--canon-space-3)}.xl\:cu-mb-4{margin-bottom:var(--canon-space-4)}.xl\:cu-mb-5{margin-bottom:var(--canon-space-5)}.xl\:cu-mb-6{margin-bottom:var(--canon-space-6)}.xl\:cu-mb-7{margin-bottom:var(--canon-space-7)}.xl\:cu-mb-8{margin-bottom:var(--canon-space-8)}.xl\:cu-mb-9{margin-bottom:var(--canon-space-9)}.xl\:cu-mb-10{margin-bottom:var(--canon-space-10)}.xl\:cu-mb-11{margin-bottom:var(--canon-space-11)}.xl\:cu-mb-12{margin-bottom:var(--canon-space-12)}.xl\:cu-mb-13{margin-bottom:var(--canon-space-13)}.xl\:cu-mb-14{margin-bottom:var(--canon-space-14)}}.cu-my{margin-top:var(--my);margin-bottom:var(--my)}.cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}@media (width>=640px){.xs\:cu-my{margin-top:var(--py-xs);margin-bottom:var(--py-xs)}.xs\:cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.xs\:cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.xs\:cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.xs\:cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.xs\:cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.xs\:cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.xs\:cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.xs\:cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.xs\:cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.xs\:cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.xs\:cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.xs\:cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.xs\:cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.xs\:cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.xs\:cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.xs\:cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-my{margin-top:var(--py-sm);margin-bottom:var(--py-sm)}.sm\:cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.sm\:cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.sm\:cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.sm\:cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.sm\:cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.sm\:cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.sm\:cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.sm\:cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.sm\:cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.sm\:cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.sm\:cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.sm\:cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.sm\:cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.sm\:cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.sm\:cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.sm\:cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-my{margin-top:var(--py-md);margin-bottom:var(--py-md)}.md\:cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.md\:cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.md\:cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.md\:cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.md\:cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.md\:cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.md\:cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.md\:cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.md\:cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.md\:cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.md\:cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.md\:cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.md\:cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.md\:cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.md\:cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.md\:cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-my{margin-top:var(--py-lg);margin-bottom:var(--py-lg)}.lg\:cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.lg\:cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.lg\:cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.lg\:cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.lg\:cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.lg\:cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.lg\:cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.lg\:cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.lg\:cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.lg\:cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.lg\:cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.lg\:cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.lg\:cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.lg\:cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.lg\:cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.lg\:cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-my{margin-top:var(--py-xl);margin-bottom:var(--py-xl)}.xl\:cu-my-0\.5{margin-top:var(--canon-space-0_5);margin-bottom:var(--canon-space-0_5)}.xl\:cu-my-1{margin-top:var(--canon-space-1);margin-bottom:var(--canon-space-1)}.xl\:cu-my-1\.5{margin-top:var(--canon-space-1_5);margin-bottom:var(--canon-space-1_5)}.xl\:cu-my-2{margin-top:var(--canon-space-2);margin-bottom:var(--canon-space-2)}.xl\:cu-my-3{margin-top:var(--canon-space-3);margin-bottom:var(--canon-space-3)}.xl\:cu-my-4{margin-top:var(--canon-space-4);margin-bottom:var(--canon-space-4)}.xl\:cu-my-5{margin-top:var(--canon-space-5);margin-bottom:var(--canon-space-5)}.xl\:cu-my-6{margin-top:var(--canon-space-6);margin-bottom:var(--canon-space-6)}.xl\:cu-my-7{margin-top:var(--canon-space-7);margin-bottom:var(--canon-space-7)}.xl\:cu-my-8{margin-top:var(--canon-space-8);margin-bottom:var(--canon-space-8)}.xl\:cu-my-9{margin-top:var(--canon-space-9);margin-bottom:var(--canon-space-9)}.xl\:cu-my-10{margin-top:var(--canon-space-10);margin-bottom:var(--canon-space-10)}.xl\:cu-my-11{margin-top:var(--canon-space-11);margin-bottom:var(--canon-space-11)}.xl\:cu-my-12{margin-top:var(--canon-space-12);margin-bottom:var(--canon-space-12)}.xl\:cu-my-13{margin-top:var(--canon-space-13);margin-bottom:var(--canon-space-13)}.xl\:cu-my-14{margin-top:var(--canon-space-14);margin-bottom:var(--canon-space-14)}}.cu-mx{margin-left:var(--mx);margin-right:var(--mx)}.cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}@media (width>=640px){.xs\:cu-mx{margin-left:var(--px-xs);margin-right:var(--px-xs)}.xs\:cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.xs\:cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.xs\:cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.xs\:cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.xs\:cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.xs\:cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.xs\:cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.xs\:cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.xs\:cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.xs\:cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.xs\:cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.xs\:cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.xs\:cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.xs\:cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.xs\:cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.xs\:cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-mx{margin-left:var(--px-sm);margin-right:var(--px-sm)}.sm\:cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.sm\:cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.sm\:cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.sm\:cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.sm\:cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.sm\:cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.sm\:cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.sm\:cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.sm\:cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.sm\:cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.sm\:cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.sm\:cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.sm\:cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.sm\:cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.sm\:cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.sm\:cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-mx{margin-left:var(--px-md);margin-right:var(--px-md)}.md\:cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.md\:cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.md\:cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.md\:cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.md\:cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.md\:cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.md\:cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.md\:cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.md\:cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.md\:cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.md\:cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.md\:cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.md\:cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.md\:cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.md\:cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.md\:cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-mx{margin-left:var(--px-lg);margin-right:var(--px-lg)}.lg\:cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.lg\:cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.lg\:cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.lg\:cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.lg\:cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.lg\:cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.lg\:cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.lg\:cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.lg\:cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.lg\:cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.lg\:cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.lg\:cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.lg\:cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.lg\:cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.lg\:cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.lg\:cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-mx{margin-left:var(--px-xl);margin-right:var(--px-xl)}.xl\:cu-mx-0\.5{margin-left:var(--canon-space-0_5);margin-right:var(--canon-space-0_5)}.xl\:cu-mx-1{margin-left:var(--canon-space-1);margin-right:var(--canon-space-1)}.xl\:cu-mx-1\.5{margin-left:var(--canon-space-1_5);margin-right:var(--canon-space-1_5)}.xl\:cu-mx-2{margin-left:var(--canon-space-2);margin-right:var(--canon-space-2)}.xl\:cu-mx-3{margin-left:var(--canon-space-3);margin-right:var(--canon-space-3)}.xl\:cu-mx-4{margin-left:var(--canon-space-4);margin-right:var(--canon-space-4)}.xl\:cu-mx-5{margin-left:var(--canon-space-5);margin-right:var(--canon-space-5)}.xl\:cu-mx-6{margin-left:var(--canon-space-6);margin-right:var(--canon-space-6)}.xl\:cu-mx-7{margin-left:var(--canon-space-7);margin-right:var(--canon-space-7)}.xl\:cu-mx-8{margin-left:var(--canon-space-8);margin-right:var(--canon-space-8)}.xl\:cu-mx-9{margin-left:var(--canon-space-9);margin-right:var(--canon-space-9)}.xl\:cu-mx-10{margin-left:var(--canon-space-10);margin-right:var(--canon-space-10)}.xl\:cu-mx-11{margin-left:var(--canon-space-11);margin-right:var(--canon-space-11)}.xl\:cu-mx-12{margin-left:var(--canon-space-12);margin-right:var(--canon-space-12)}.xl\:cu-mx-13{margin-left:var(--canon-space-13);margin-right:var(--canon-space-13)}.xl\:cu-mx-14{margin-left:var(--canon-space-14);margin-right:var(--canon-space-14)}}.cu-display-none{display:none}.cu-display-inline{display:inline}.cu-display-inline-block{display:inline-block}.cu-display-block{display:block}@media (width>=640px){.xs\:cu-display-none{display:none}.xs\:cu-display-inline{display:inline}.xs\:cu-display-inline-block{display:inline-block}.xs\:cu-display-block{display:block}}@media (width>=768px){.sm\:cu-display-none{display:none}.sm\:cu-display-inline{display:inline}.sm\:cu-display-inline-block{display:inline-block}.sm\:cu-display-block{display:block}}@media (width>=1024px){.md\:cu-display-none{display:none}.md\:cu-display-inline{display:inline}.md\:cu-display-inline-block{display:inline-block}.md\:cu-display-block{display:block}}@media (width>=1280px){.lg\:cu-display-none{display:none}.lg\:cu-display-inline{display:inline}.lg\:cu-display-inline-block{display:inline-block}.lg\:cu-display-block{display:block}}@media (width>=1536px){.xl\:cu-display-none{display:none}.xl\:cu-display-inline{display:inline}.xl\:cu-display-inline-block{display:inline-block}.xl\:cu-display-block{display:block}}.cu-w{width:var(--width)}.cu-min-w{min-width:var(--min-width)}.cu-max-w{max-width:var(--max-width)}@media (width>=640px){.xs\:cu-w{width:var(--width)}.xs\:cu-min-w{min-width:var(--min-width)}.xs\:cu-max-w{max-width:var(--max-width)}}@media (width>=768px){.sm\:cu-w{width:var(--width)}.sm\:cu-min-w{min-width:var(--min-width)}.sm\:cu-max-w{max-width:var(--max-width)}}@media (width>=1024px){.md\:cu-w{width:var(--width)}.md\:cu-min-w{min-width:var(--min-width)}.md\:cu-max-w{max-width:var(--max-width)}}@media (width>=1280px){.lg\:cu-w{width:var(--width)}.lg\:cu-min-w{min-width:var(--min-width)}.lg\:cu-max-w{max-width:var(--max-width)}}@media (width>=1536px){.xl\:cu-w{width:var(--width)}.xl\:cu-min-w{min-width:var(--min-width)}.xl\:cu-max-w{max-width:var(--max-width)}}.cu-h{height:var(--height)}.cu-min-h{min-height:var(--min-height)}.cu-max-h{max-height:var(--max-height)}@media (width>=640px){.xs\:cu-h{height:var(--height)}.xs\:cu-min-h{min-height:var(--min-height)}.xs\:cu-max-h{max-height:var(--max-height)}}@media (width>=768px){.sm\:cu-h{height:var(--height)}.sm\:cu-min-h{min-height:var(--min-height)}.sm\:cu-max-h{max-height:var(--max-height)}}@media (width>=1024px){.md\:cu-h{height:var(--height)}.md\:cu-min-h{min-height:var(--min-height)}.md\:cu-max-h{max-height:var(--max-height)}}@media (width>=1280px){.lg\:cu-h{height:var(--height)}.lg\:cu-min-h{min-height:var(--min-height)}.lg\:cu-max-h{max-height:var(--max-height)}}@media (width>=1536px){.xl\:cu-h{height:var(--height)}.xl\:cu-min-h{min-height:var(--min-height)}.xl\:cu-max-h{max-height:var(--max-height)}}.cu-position-absolute{position:absolute}.cu-position-fixed{position:fixed}.cu-position-sticky{position:sticky}.cu-position-relative{position:relative}.cu-position-static{position:static}@media (width>=640px){.xs\:cu-position-absolute{position:absolute}.xs\:cu-position-fixed{position:fixed}.xs\:cu-position-sticky{position:sticky}.xs\:cu-position-relative{position:relative}.xs\:cu-position-static{position:static}}@media (width>=768px){.sm\:cu-position-absolute{position:absolute}.sm\:cu-position-fixed{position:fixed}.sm\:cu-position-sticky{position:sticky}.sm\:cu-position-relative{position:relative}.sm\:cu-position-static{position:static}}@media (width>=1024px){.md\:cu-position-absolute{position:absolute}.md\:cu-position-fixed{position:fixed}.md\:cu-position-sticky{position:sticky}.md\:cu-position-relative{position:relative}.md\:cu-position-static{position:static}}@media (width>=1280px){.lg\:cu-position-absolute{position:absolute}.lg\:cu-position-fixed{position:fixed}.lg\:cu-position-sticky{position:sticky}.lg\:cu-position-relative{position:relative}.lg\:cu-position-static{position:static}}@media (width>=1536px){.xl\:cu-position-absolute{position:absolute}.xl\:cu-position-fixed{position:fixed}.xl\:cu-position-sticky{position:sticky}.xl\:cu-position-relative{position:relative}.xl\:cu-position-static{position:static}}.cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.cu-col-span-1{grid-column:span 1/span 1}.cu-col-span-2{grid-column:span 2/span 2}.cu-col-span-3{grid-column:span 3/span 3}.cu-col-span-4{grid-column:span 4/span 4}.cu-col-span-5{grid-column:span 5/span 5}.cu-col-span-6{grid-column:span 6/span 6}.cu-col-span-7{grid-column:span 7/span 7}.cu-col-span-8{grid-column:span 8/span 8}.cu-col-span-9{grid-column:span 9/span 9}.cu-col-span-10{grid-column:span 10/span 10}.cu-col-span-11{grid-column:span 11/span 11}.cu-col-span-12{grid-column:span 12/span 12}.cu-col-span-auto{grid-column:span auto/span auto}.cu-col-start-1{grid-column-start:1}.cu-col-start-2{grid-column-start:2}.cu-col-start-3{grid-column-start:3}.cu-col-start-4{grid-column-start:4}.cu-col-start-5{grid-column-start:5}.cu-col-start-6{grid-column-start:6}.cu-col-start-7{grid-column-start:7}.cu-col-start-8{grid-column-start:8}.cu-col-start-9{grid-column-start:9}.cu-col-start-10{grid-column-start:10}.cu-col-start-11{grid-column-start:11}.cu-col-start-12{grid-column-start:12}.cu-col-start-13{grid-column-start:13}.cu-col-start-auto{grid-column-start:auto}.cu-col-end-1{grid-column-end:1}.cu-col-end-2{grid-column-end:2}.cu-col-end-3{grid-column-end:3}.cu-col-end-4{grid-column-end:4}.cu-col-end-5{grid-column-end:5}.cu-col-end-6{grid-column-end:6}.cu-col-end-7{grid-column-end:7}.cu-col-end-8{grid-column-end:8}.cu-col-end-9{grid-column-end:9}.cu-col-end-10{grid-column-end:10}.cu-col-end-11{grid-column-end:11}.cu-col-end-12{grid-column-end:12}.cu-col-end-13{grid-column-end:13}.cu-col-end-auto{grid-column-end:auto}.cu-row-span-1{grid-row:span 1/span 1}.cu-row-span-2{grid-row:span 2/span 2}.cu-row-span-3{grid-row:span 3/span 3}.cu-row-span-4{grid-row:span 4/span 4}.cu-row-span-5{grid-row:span 5/span 5}.cu-row-span-6{grid-row:span 6/span 6}.cu-row-span-7{grid-row:span 7/span 7}.cu-row-span-8{grid-row:span 8/span 8}.cu-row-span-9{grid-row:span 9/span 9}.cu-row-span-10{grid-row:span 10/span 10}.cu-row-span-11{grid-row:span 11/span 11}.cu-row-span-12{grid-row:span 12/span 12}.cu-row-span-auto{grid-row:span auto/span auto}@media (width>=640px){.xs\:cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xs\:cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xs\:cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xs\:cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xs\:cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xs\:cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xs\:cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xs\:cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xs\:cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xs\:cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xs\:cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xs\:cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xs\:cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xs\:cu-col-span-1{grid-column:span 1/span 1}.xs\:cu-col-span-2{grid-column:span 2/span 2}.xs\:cu-col-span-3{grid-column:span 3/span 3}.xs\:cu-col-span-4{grid-column:span 4/span 4}.xs\:cu-col-span-5{grid-column:span 5/span 5}.xs\:cu-col-span-6{grid-column:span 6/span 6}.xs\:cu-col-span-7{grid-column:span 7/span 7}.xs\:cu-col-span-8{grid-column:span 8/span 8}.xs\:cu-col-span-9{grid-column:span 9/span 9}.xs\:cu-col-span-10{grid-column:span 10/span 10}.xs\:cu-col-span-11{grid-column:span 11/span 11}.xs\:cu-col-span-12{grid-column:span 12/span 12}.xs\:cu-col-span-auto{grid-column:span auto/span auto}.xs\:cu-col-start-1{grid-column-start:1}.xs\:cu-col-start-2{grid-column-start:2}.xs\:cu-col-start-3{grid-column-start:3}.xs\:cu-col-start-4{grid-column-start:4}.xs\:cu-col-start-5{grid-column-start:5}.xs\:cu-col-start-6{grid-column-start:6}.xs\:cu-col-start-7{grid-column-start:7}.xs\:cu-col-start-8{grid-column-start:8}.xs\:cu-col-start-9{grid-column-start:9}.xs\:cu-col-start-10{grid-column-start:10}.xs\:cu-col-start-11{grid-column-start:11}.xs\:cu-col-start-12{grid-column-start:12}.xs\:cu-col-start-13{grid-column-start:13}.xs\:cu-col-start-auto{grid-column-start:auto}.xs\:cu-col-end-1{grid-column-end:1}.xs\:cu-col-end-2{grid-column-end:2}.xs\:cu-col-end-3{grid-column-end:3}.xs\:cu-col-end-4{grid-column-end:4}.xs\:cu-col-end-5{grid-column-end:5}.xs\:cu-col-end-6{grid-column-end:6}.xs\:cu-col-end-7{grid-column-end:7}.xs\:cu-col-end-8{grid-column-end:8}.xs\:cu-col-end-9{grid-column-end:9}.xs\:cu-col-end-10{grid-column-end:10}.xs\:cu-col-end-11{grid-column-end:11}.xs\:cu-col-end-12{grid-column-end:12}.xs\:cu-col-end-13{grid-column-end:13}.xs\:cu-col-end-auto{grid-column-end:auto}.xs\:cu-row-span-1{grid-row:span 1/span 1}.xs\:cu-row-span-2{grid-row:span 2/span 2}.xs\:cu-row-span-3{grid-row:span 3/span 3}.xs\:cu-row-span-4{grid-row:span 4/span 4}.xs\:cu-row-span-5{grid-row:span 5/span 5}.xs\:cu-row-span-6{grid-row:span 6/span 6}.xs\:cu-row-span-7{grid-row:span 7/span 7}.xs\:cu-row-span-8{grid-row:span 8/span 8}.xs\:cu-row-span-9{grid-row:span 9/span 9}.xs\:cu-row-span-10{grid-row:span 10/span 10}.xs\:cu-row-span-11{grid-row:span 11/span 11}.xs\:cu-row-span-12{grid-row:span 12/span 12}.xs\:cu-row-span-auto{grid-row:span auto/span auto}}@media (width>=768px){.sm\:cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.sm\:cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.sm\:cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.sm\:cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\:cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.sm\:cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.sm\:cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.sm\:cu-col-span-1{grid-column:span 1/span 1}.sm\:cu-col-span-2{grid-column:span 2/span 2}.sm\:cu-col-span-3{grid-column:span 3/span 3}.sm\:cu-col-span-4{grid-column:span 4/span 4}.sm\:cu-col-span-5{grid-column:span 5/span 5}.sm\:cu-col-span-6{grid-column:span 6/span 6}.sm\:cu-col-span-7{grid-column:span 7/span 7}.sm\:cu-col-span-8{grid-column:span 8/span 8}.sm\:cu-col-span-9{grid-column:span 9/span 9}.sm\:cu-col-span-10{grid-column:span 10/span 10}.sm\:cu-col-span-11{grid-column:span 11/span 11}.sm\:cu-col-span-12{grid-column:span 12/span 12}.sm\:cu-col-span-auto{grid-column:span auto/span auto}.sm\:cu-col-start-1{grid-column-start:1}.sm\:cu-col-start-2{grid-column-start:2}.sm\:cu-col-start-3{grid-column-start:3}.sm\:cu-col-start-4{grid-column-start:4}.sm\:cu-col-start-5{grid-column-start:5}.sm\:cu-col-start-6{grid-column-start:6}.sm\:cu-col-start-7{grid-column-start:7}.sm\:cu-col-start-8{grid-column-start:8}.sm\:cu-col-start-9{grid-column-start:9}.sm\:cu-col-start-10{grid-column-start:10}.sm\:cu-col-start-11{grid-column-start:11}.sm\:cu-col-start-12{grid-column-start:12}.sm\:cu-col-start-13{grid-column-start:13}.sm\:cu-col-start-auto{grid-column-start:auto}.sm\:cu-col-end-1{grid-column-end:1}.sm\:cu-col-end-2{grid-column-end:2}.sm\:cu-col-end-3{grid-column-end:3}.sm\:cu-col-end-4{grid-column-end:4}.sm\:cu-col-end-5{grid-column-end:5}.sm\:cu-col-end-6{grid-column-end:6}.sm\:cu-col-end-7{grid-column-end:7}.sm\:cu-col-end-8{grid-column-end:8}.sm\:cu-col-end-9{grid-column-end:9}.sm\:cu-col-end-10{grid-column-end:10}.sm\:cu-col-end-11{grid-column-end:11}.sm\:cu-col-end-12{grid-column-end:12}.sm\:cu-col-end-13{grid-column-end:13}.sm\:cu-col-end-auto{grid-column-end:auto}.sm\:cu-row-span-1{grid-row:span 1/span 1}.sm\:cu-row-span-2{grid-row:span 2/span 2}.sm\:cu-row-span-3{grid-row:span 3/span 3}.sm\:cu-row-span-4{grid-row:span 4/span 4}.sm\:cu-row-span-5{grid-row:span 5/span 5}.sm\:cu-row-span-6{grid-row:span 6/span 6}.sm\:cu-row-span-7{grid-row:span 7/span 7}.sm\:cu-row-span-8{grid-row:span 8/span 8}.sm\:cu-row-span-9{grid-row:span 9/span 9}.sm\:cu-row-span-10{grid-row:span 10/span 10}.sm\:cu-row-span-11{grid-row:span 11/span 11}.sm\:cu-row-span-12{grid-row:span 12/span 12}.sm\:cu-row-span-auto{grid-row:span auto/span auto}}@media (width>=1024px){.md\:cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.md\:cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.md\:cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.md\:cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.md\:cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.md\:cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.md\:cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.md\:cu-col-span-1{grid-column:span 1/span 1}.md\:cu-col-span-2{grid-column:span 2/span 2}.md\:cu-col-span-3{grid-column:span 3/span 3}.md\:cu-col-span-4{grid-column:span 4/span 4}.md\:cu-col-span-5{grid-column:span 5/span 5}.md\:cu-col-span-6{grid-column:span 6/span 6}.md\:cu-col-span-7{grid-column:span 7/span 7}.md\:cu-col-span-8{grid-column:span 8/span 8}.md\:cu-col-span-9{grid-column:span 9/span 9}.md\:cu-col-span-10{grid-column:span 10/span 10}.md\:cu-col-span-11{grid-column:span 11/span 11}.md\:cu-col-span-12{grid-column:span 12/span 12}.md\:cu-col-span-auto{grid-column:span auto/span auto}.md\:cu-col-start-1{grid-column-start:1}.md\:cu-col-start-2{grid-column-start:2}.md\:cu-col-start-3{grid-column-start:3}.md\:cu-col-start-4{grid-column-start:4}.md\:cu-col-start-5{grid-column-start:5}.md\:cu-col-start-6{grid-column-start:6}.md\:cu-col-start-7{grid-column-start:7}.md\:cu-col-start-8{grid-column-start:8}.md\:cu-col-start-9{grid-column-start:9}.md\:cu-col-start-10{grid-column-start:10}.md\:cu-col-start-11{grid-column-start:11}.md\:cu-col-start-12{grid-column-start:12}.md\:cu-col-start-13{grid-column-start:13}.md\:cu-col-start-auto{grid-column-start:auto}.md\:cu-col-end-1{grid-column-end:1}.md\:cu-col-end-2{grid-column-end:2}.md\:cu-col-end-3{grid-column-end:3}.md\:cu-col-end-4{grid-column-end:4}.md\:cu-col-end-5{grid-column-end:5}.md\:cu-col-end-6{grid-column-end:6}.md\:cu-col-end-7{grid-column-end:7}.md\:cu-col-end-8{grid-column-end:8}.md\:cu-col-end-9{grid-column-end:9}.md\:cu-col-end-10{grid-column-end:10}.md\:cu-col-end-11{grid-column-end:11}.md\:cu-col-end-12{grid-column-end:12}.md\:cu-col-end-13{grid-column-end:13}.md\:cu-col-end-auto{grid-column-end:auto}.md\:cu-row-span-1{grid-row:span 1/span 1}.md\:cu-row-span-2{grid-row:span 2/span 2}.md\:cu-row-span-3{grid-row:span 3/span 3}.md\:cu-row-span-4{grid-row:span 4/span 4}.md\:cu-row-span-5{grid-row:span 5/span 5}.md\:cu-row-span-6{grid-row:span 6/span 6}.md\:cu-row-span-7{grid-row:span 7/span 7}.md\:cu-row-span-8{grid-row:span 8/span 8}.md\:cu-row-span-9{grid-row:span 9/span 9}.md\:cu-row-span-10{grid-row:span 10/span 10}.md\:cu-row-span-11{grid-row:span 11/span 11}.md\:cu-row-span-12{grid-row:span 12/span 12}.md\:cu-row-span-auto{grid-row:span auto/span auto}}@media (width>=1280px){.lg\:cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.lg\:cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.lg\:cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.lg\:cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.lg\:cu-col-span-1{grid-column:span 1/span 1}.lg\:cu-col-span-2{grid-column:span 2/span 2}.lg\:cu-col-span-3{grid-column:span 3/span 3}.lg\:cu-col-span-4{grid-column:span 4/span 4}.lg\:cu-col-span-5{grid-column:span 5/span 5}.lg\:cu-col-span-6{grid-column:span 6/span 6}.lg\:cu-col-span-7{grid-column:span 7/span 7}.lg\:cu-col-span-8{grid-column:span 8/span 8}.lg\:cu-col-span-9{grid-column:span 9/span 9}.lg\:cu-col-span-10{grid-column:span 10/span 10}.lg\:cu-col-span-11{grid-column:span 11/span 11}.lg\:cu-col-span-12{grid-column:span 12/span 12}.lg\:cu-col-span-auto{grid-column:span auto/span auto}.lg\:cu-col-start-1{grid-column-start:1}.lg\:cu-col-start-2{grid-column-start:2}.lg\:cu-col-start-3{grid-column-start:3}.lg\:cu-col-start-4{grid-column-start:4}.lg\:cu-col-start-5{grid-column-start:5}.lg\:cu-col-start-6{grid-column-start:6}.lg\:cu-col-start-7{grid-column-start:7}.lg\:cu-col-start-8{grid-column-start:8}.lg\:cu-col-start-9{grid-column-start:9}.lg\:cu-col-start-10{grid-column-start:10}.lg\:cu-col-start-11{grid-column-start:11}.lg\:cu-col-start-12{grid-column-start:12}.lg\:cu-col-start-13{grid-column-start:13}.lg\:cu-col-start-auto{grid-column-start:auto}.lg\:cu-col-end-1{grid-column-end:1}.lg\:cu-col-end-2{grid-column-end:2}.lg\:cu-col-end-3{grid-column-end:3}.lg\:cu-col-end-4{grid-column-end:4}.lg\:cu-col-end-5{grid-column-end:5}.lg\:cu-col-end-6{grid-column-end:6}.lg\:cu-col-end-7{grid-column-end:7}.lg\:cu-col-end-8{grid-column-end:8}.lg\:cu-col-end-9{grid-column-end:9}.lg\:cu-col-end-10{grid-column-end:10}.lg\:cu-col-end-11{grid-column-end:11}.lg\:cu-col-end-12{grid-column-end:12}.lg\:cu-col-end-13{grid-column-end:13}.lg\:cu-col-end-auto{grid-column-end:auto}.lg\:cu-row-span-1{grid-row:span 1/span 1}.lg\:cu-row-span-2{grid-row:span 2/span 2}.lg\:cu-row-span-3{grid-row:span 3/span 3}.lg\:cu-row-span-4{grid-row:span 4/span 4}.lg\:cu-row-span-5{grid-row:span 5/span 5}.lg\:cu-row-span-6{grid-row:span 6/span 6}.lg\:cu-row-span-7{grid-row:span 7/span 7}.lg\:cu-row-span-8{grid-row:span 8/span 8}.lg\:cu-row-span-9{grid-row:span 9/span 9}.lg\:cu-row-span-10{grid-row:span 10/span 10}.lg\:cu-row-span-11{grid-row:span 11/span 11}.lg\:cu-row-span-12{grid-row:span 12/span 12}.lg\:cu-row-span-auto{grid-row:span auto/span auto}}@media (width>=1536px){.xl\:cu-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xl\:cu-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:cu-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:cu-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:cu-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:cu-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xl\:cu-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xl\:cu-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xl\:cu-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xl\:cu-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:cu-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xl\:cu-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xl\:cu-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xl\:cu-col-span-1{grid-column:span 1/span 1}.xl\:cu-col-span-2{grid-column:span 2/span 2}.xl\:cu-col-span-3{grid-column:span 3/span 3}.xl\:cu-col-span-4{grid-column:span 4/span 4}.xl\:cu-col-span-5{grid-column:span 5/span 5}.xl\:cu-col-span-6{grid-column:span 6/span 6}.xl\:cu-col-span-7{grid-column:span 7/span 7}.xl\:cu-col-span-8{grid-column:span 8/span 8}.xl\:cu-col-span-9{grid-column:span 9/span 9}.xl\:cu-col-span-10{grid-column:span 10/span 10}.xl\:cu-col-span-11{grid-column:span 11/span 11}.xl\:cu-col-span-12{grid-column:span 12/span 12}.xl\:cu-col-span-auto{grid-column:span auto/span auto}.xl\:cu-col-start-1{grid-column-start:1}.xl\:cu-col-start-2{grid-column-start:2}.xl\:cu-col-start-3{grid-column-start:3}.xl\:cu-col-start-4{grid-column-start:4}.xl\:cu-col-start-5{grid-column-start:5}.xl\:cu-col-start-6{grid-column-start:6}.xl\:cu-col-start-7{grid-column-start:7}.xl\:cu-col-start-8{grid-column-start:8}.xl\:cu-col-start-9{grid-column-start:9}.xl\:cu-col-start-10{grid-column-start:10}.xl\:cu-col-start-11{grid-column-start:11}.xl\:cu-col-start-12{grid-column-start:12}.xl\:cu-col-start-13{grid-column-start:13}.xl\:cu-col-start-auto{grid-column-start:auto}.xl\:cu-col-end-1{grid-column-end:1}.xl\:cu-col-end-2{grid-column-end:2}.xl\:cu-col-end-3{grid-column-end:3}.xl\:cu-col-end-4{grid-column-end:4}.xl\:cu-col-end-5{grid-column-end:5}.xl\:cu-col-end-6{grid-column-end:6}.xl\:cu-col-end-7{grid-column-end:7}.xl\:cu-col-end-8{grid-column-end:8}.xl\:cu-col-end-9{grid-column-end:9}.xl\:cu-col-end-10{grid-column-end:10}.xl\:cu-col-end-11{grid-column-end:11}.xl\:cu-col-end-12{grid-column-end:12}.xl\:cu-col-end-13{grid-column-end:13}.xl\:cu-col-end-auto{grid-column-end:auto}.xl\:cu-row-span-1{grid-row:span 1/span 1}.xl\:cu-row-span-2{grid-row:span 2/span 2}.xl\:cu-row-span-3{grid-row:span 3/span 3}.xl\:cu-row-span-4{grid-row:span 4/span 4}.xl\:cu-row-span-5{grid-row:span 5/span 5}.xl\:cu-row-span-6{grid-row:span 6/span 6}.xl\:cu-row-span-7{grid-row:span 7/span 7}.xl\:cu-row-span-8{grid-row:span 8/span 8}.xl\:cu-row-span-9{grid-row:span 9/span 9}.xl\:cu-row-span-10{grid-row:span 10/span 10}.xl\:cu-row-span-11{grid-row:span 11/span 11}.xl\:cu-row-span-12{grid-row:span 12/span 12}.xl\:cu-row-span-auto{grid-row:span auto/span auto}}.cu-gap{gap:var(--gap)}.cu-gap-0\.5{gap:var(--canon-space-0_5)}.cu-gap-1{gap:var(--canon-space-1)}.cu-gap-1\.5{gap:var(--canon-space-1_5)}.cu-gap-2{gap:var(--canon-space-2)}.cu-gap-3{gap:var(--canon-space-3)}.cu-gap-4{gap:var(--canon-space-4)}.cu-gap-5{gap:var(--canon-space-5)}.cu-gap-6{gap:var(--canon-space-6)}.cu-gap-7{gap:var(--canon-space-7)}.cu-gap-8{gap:var(--canon-space-8)}.cu-gap-9{gap:var(--canon-space-9)}.cu-gap-10{gap:var(--canon-space-10)}.cu-gap-11{gap:var(--canon-space-11)}.cu-gap-12{gap:var(--canon-space-12)}.cu-gap-13{gap:var(--canon-space-13)}.cu-gap-14{gap:var(--canon-space-14)}@media (width>=640px){.xs\:cu-gap{gap:var(--gap-xs)}.xs\:cu-gap-0\.5{gap:var(--canon-space-0_5)}.xs\:cu-gap-1{gap:var(--canon-space-1)}.xs\:cu-gap-1\.5{gap:var(--canon-space-1_5)}.xs\:cu-gap-2{gap:var(--canon-space-2)}.xs\:cu-gap-3{gap:var(--canon-space-3)}.xs\:cu-gap-4{gap:var(--canon-space-4)}.xs\:cu-gap-5{gap:var(--canon-space-5)}.xs\:cu-gap-6{gap:var(--canon-space-6)}.xs\:cu-gap-7{gap:var(--canon-space-7)}.xs\:cu-gap-8{gap:var(--canon-space-8)}.xs\:cu-gap-9{gap:var(--canon-space-9)}.xs\:cu-gap-10{gap:var(--canon-space-10)}.xs\:cu-gap-11{gap:var(--canon-space-11)}.xs\:cu-gap-12{gap:var(--canon-space-12)}.xs\:cu-gap-13{gap:var(--canon-space-13)}.xs\:cu-gap-14{gap:var(--canon-space-14)}}@media (width>=768px){.sm\:cu-gap{gap:var(--gap-sm)}.sm\:cu-gap-0\.5{gap:var(--canon-space-0_5)}.sm\:cu-gap-1{gap:var(--canon-space-1)}.sm\:cu-gap-1\.5{gap:var(--canon-space-1_5)}.sm\:cu-gap-2{gap:var(--canon-space-2)}.sm\:cu-gap-3{gap:var(--canon-space-3)}.sm\:cu-gap-4{gap:var(--canon-space-4)}.sm\:cu-gap-5{gap:var(--canon-space-5)}.sm\:cu-gap-6{gap:var(--canon-space-6)}.sm\:cu-gap-7{gap:var(--canon-space-7)}.sm\:cu-gap-8{gap:var(--canon-space-8)}.sm\:cu-gap-9{gap:var(--canon-space-9)}.sm\:cu-gap-10{gap:var(--canon-space-10)}.sm\:cu-gap-11{gap:var(--canon-space-11)}.sm\:cu-gap-12{gap:var(--canon-space-12)}.sm\:cu-gap-13{gap:var(--canon-space-13)}.sm\:cu-gap-14{gap:var(--canon-space-14)}}@media (width>=1024px){.md\:cu-gap{gap:var(--gap-md)}.md\:cu-gap-0\.5{gap:var(--canon-space-0_5)}.md\:cu-gap-1{gap:var(--canon-space-1)}.md\:cu-gap-1\.5{gap:var(--canon-space-1_5)}.md\:cu-gap-2{gap:var(--canon-space-2)}.md\:cu-gap-3{gap:var(--canon-space-3)}.md\:cu-gap-4{gap:var(--canon-space-4)}.md\:cu-gap-5{gap:var(--canon-space-5)}.md\:cu-gap-6{gap:var(--canon-space-6)}.md\:cu-gap-7{gap:var(--canon-space-7)}.md\:cu-gap-8{gap:var(--canon-space-8)}.md\:cu-gap-9{gap:var(--canon-space-9)}.md\:cu-gap-10{gap:var(--canon-space-10)}.md\:cu-gap-11{gap:var(--canon-space-11)}.md\:cu-gap-12{gap:var(--canon-space-12)}.md\:cu-gap-13{gap:var(--canon-space-13)}.md\:cu-gap-14{gap:var(--canon-space-14)}}@media (width>=1280px){.lg\:cu-gap{gap:var(--gap-lg)}.lg\:cu-gap-0\.5{gap:var(--canon-space-0_5)}.lg\:cu-gap-1{gap:var(--canon-space-1)}.lg\:cu-gap-1\.5{gap:var(--canon-space-1_5)}.lg\:cu-gap-2{gap:var(--canon-space-2)}.lg\:cu-gap-3{gap:var(--canon-space-3)}.lg\:cu-gap-4{gap:var(--canon-space-4)}.lg\:cu-gap-5{gap:var(--canon-space-5)}.lg\:cu-gap-6{gap:var(--canon-space-6)}.lg\:cu-gap-7{gap:var(--canon-space-7)}.lg\:cu-gap-8{gap:var(--canon-space-8)}.lg\:cu-gap-9{gap:var(--canon-space-9)}.lg\:cu-gap-10{gap:var(--canon-space-10)}.lg\:cu-gap-11{gap:var(--canon-space-11)}.lg\:cu-gap-12{gap:var(--canon-space-12)}.lg\:cu-gap-13{gap:var(--canon-space-13)}.lg\:cu-gap-14{gap:var(--canon-space-14)}}@media (width>=1536px){.xl\:cu-gap{gap:var(--gap-xl)}.xl\:cu-gap-0\.5{gap:var(--canon-space-0_5)}.xl\:cu-gap-1{gap:var(--canon-space-1)}.xl\:cu-gap-1\.5{gap:var(--canon-space-1_5)}.xl\:cu-gap-2{gap:var(--canon-space-2)}.xl\:cu-gap-3{gap:var(--canon-space-3)}.xl\:cu-gap-4{gap:var(--canon-space-4)}.xl\:cu-gap-5{gap:var(--canon-space-5)}.xl\:cu-gap-6{gap:var(--canon-space-6)}.xl\:cu-gap-7{gap:var(--canon-space-7)}.xl\:cu-gap-8{gap:var(--canon-space-8)}.xl\:cu-gap-9{gap:var(--canon-space-9)}.xl\:cu-gap-10{gap:var(--canon-space-10)}.xl\:cu-gap-11{gap:var(--canon-space-11)}.xl\:cu-gap-12{gap:var(--canon-space-12)}.xl\:cu-gap-13{gap:var(--canon-space-13)}.xl\:cu-gap-14{gap:var(--canon-space-14)}}.cu-align-start{align-items:start}.cu-align-center{align-items:center}.cu-align-end{align-items:end}.cu-align-stretch{align-items:stretch}.cu-jc-start{justify-content:start}.cu-jc-center{justify-content:center}.cu-jc-end{justify-content:end}.cu-jc-between{justify-content:space-between}.cu-fd-row{flex-direction:row}.cu-fd-column{flex-direction:column}.cu-fd-row-reverse{flex-direction:row-reverse}.cu-fd-column-reverse{flex-direction:column-reverse}@media (width>=640px){.xs\:cu-align-start{align-items:start}.xs\:cu-align-center{align-items:center}.xs\:cu-align-end{align-items:end}.xs\:cu-align-stretch{align-items:stretch}.xs\:cu-jc-start{justify-content:start}.xs\:cu-jc-center{justify-content:center}.xs\:cu-jc-end{justify-content:end}.xs\:cu-jc-between{justify-content:space-between}.xs\:cu-fd-row{flex-direction:row}.xs\:cu-fd-column{flex-direction:column}.xs\:cu-fd-row-reverse{flex-direction:row-reverse}.xs\:cu-fd-column-reverse{flex-direction:column-reverse}}@media (width>=768px){.sm\:cu-align-start{align-items:start}.sm\:cu-align-center{align-items:center}.sm\:cu-align-end{align-items:end}.sm\:cu-align-stretch{align-items:stretch}.sm\:cu-jc-start{justify-content:start}.sm\:cu-jc-center{justify-content:center}.sm\:cu-jc-end{justify-content:end}.sm\:cu-jc-between{justify-content:space-between}.sm\:cu-fd-row{flex-direction:row}.sm\:cu-fd-column{flex-direction:column}.sm\:cu-fd-row-reverse{flex-direction:row-reverse}.sm\:cu-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1024px){.md\:cu-align-start{align-items:start}.md\:cu-align-center{align-items:center}.md\:cu-align-end{align-items:end}.md\:cu-align-stretch{align-items:stretch}.md\:cu-jc-start{justify-content:start}.md\:cu-jc-center{justify-content:center}.md\:cu-jc-end{justify-content:end}.md\:cu-jc-between{justify-content:space-between}.md\:cu-fd-row{flex-direction:row}.md\:cu-fd-column{flex-direction:column}.md\:cu-fd-row-reverse{flex-direction:row-reverse}.md\:cu-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1280px){.lg\:cu-align-start{align-items:start}.lg\:cu-align-center{align-items:center}.lg\:cu-align-end{align-items:end}.lg\:cu-align-stretch{align-items:stretch}.lg\:cu-jc-start{justify-content:start}.lg\:cu-jc-center{justify-content:center}.lg\:cu-jc-end{justify-content:end}.lg\:cu-jc-between{justify-content:space-between}.lg\:cu-fd-row{flex-direction:row}.lg\:cu-fd-column{flex-direction:column}.lg\:cu-fd-row-reverse{flex-direction:row-reverse}.lg\:cu-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1536px){.xl\:cu-align-start{align-items:start}.xl\:cu-align-center{align-items:center}.xl\:cu-align-end{align-items:end}.xl\:cu-align-stretch{align-items:stretch}.xl\:cu-jc-start{justify-content:start}.xl\:cu-jc-center{justify-content:center}.xl\:cu-jc-end{justify-content:end}.xl\:cu-jc-between{justify-content:space-between}.xl\:cu-fd-row{flex-direction:row}.xl\:cu-fd-column{flex-direction:column}.xl\:cu-fd-row-reverse{flex-direction:row-reverse}.xl\:cu-fd-column-reverse{flex-direction:column-reverse}}:where(a){color:inherit;text-decoration:none}:root{--canon-font-regular:system-ui;--canon-font-monospace:ui-monospace,"Menlo","Monaco","Consolas","Liberation Mono","Courier New",monospace;--canon-font-weight-regular:400;--canon-font-weight-bold:600;--canon-font-size-1:.625rem;--canon-font-size-2:.75rem;--canon-font-size-3:.875rem;--canon-font-size-4:1rem;--canon-font-size-5:1.25rem;--canon-font-size-6:1.5rem;--canon-font-size-7:2rem;--canon-font-size-8:3rem;--canon-font-size-9:4rem;--canon-font-size-10:5.75rem;--canon-space:.25rem;--canon-space-0_5:calc(var(--canon-space)*.5);--canon-space-1:var(--canon-space);--canon-space-1_5:calc(var(--canon-space)*1.5);--canon-space-2:calc(var(--canon-space)*2);--canon-space-3:calc(var(--canon-space)*3);--canon-space-4:calc(var(--canon-space)*4);--canon-space-5:calc(var(--canon-space)*5);--canon-space-6:calc(var(--canon-space)*6);--canon-space-7:calc(var(--canon-space)*7);--canon-space-8:calc(var(--canon-space)*8);--canon-space-9:calc(var(--canon-space)*9);--canon-space-10:calc(var(--canon-space)*10);--canon-space-11:calc(var(--canon-space)*11);--canon-space-12:calc(var(--canon-space)*12);--canon-space-13:calc(var(--canon-space)*13);--canon-space-14:calc(var(--canon-space)*14);--canon-radius-1:calc(.125rem);--canon-radius-2:calc(.25rem);--canon-radius-3:calc(.5rem);--canon-radius-4:calc(.75rem);--canon-radius-5:calc(1rem);--canon-radius-6:calc(1.25rem);--canon-radius-full:9999px;--canon-black:#000;--canon-white:#fff;--canon-gray-1:#f8f8f8;--canon-gray-2:#ececec;--canon-gray-3:#d9d9d9;--canon-gray-4:#c1c1c1;--canon-gray-5:#9e9e9e;--canon-gray-6:#8c8c8c;--canon-gray-7:#757575;--canon-gray-8:#595959;--canon-bg:var(--canon-gray-1);--canon-bg-surface-1:var(--canon-white);--canon-bg-surface-2:var(--canon-gray-2);--canon-bg-solid:#1f5493;--canon-bg-solid-hover:#163a66;--canon-bg-solid-pressed:#0f2b4e;--canon-bg-solid-disabled:#ebebeb;--canon-bg-tint:transparent;--canon-bg-tint-hover:#1f549366;--canon-bg-tint-pressed:#1f549399;--canon-bg-tint-disabled:#ebebeb;--canon-bg-danger:#feebe7;--canon-bg-warning:#fff2b2;--canon-bg-success:#e6f6eb;--canon-fg-primary:var(--canon-black);--canon-fg-secondary:var(--canon-gray-7);--canon-fg-link:#1f5493;--canon-fg-link-hover:#1f2d5c;--canon-fg-disabled:#9e9e9e;--canon-fg-solid:var(--canon-white);--canon-fg-solid-disabled:#9c9c9c;--canon-fg-tint:#1f5493;--canon-fg-tint-disabled:var(--canon-gray-5);--canon-fg-danger:#e22b2b;--canon-fg-warning:#e36d05;--canon-fg-success:#1db954;--canon-border:#0000001a;--canon-border-hover:#0003;--canon-border-pressed:#0006;--canon-border-disabled:#0000001a;--canon-border-danger:#f87a7a;--canon-border-warning:#e36d05;--canon-border-success:#53db83;--canon-ring:#1f5493;--canon-scrollbar:#a0a0a03b;--canon-scrollbar-thumb:#a0a0a0}[data-theme=dark]{--canon-gray-1:#191919;--canon-gray-2:#242424;--canon-gray-3:#373737;--canon-gray-4:#464646;--canon-gray-5:#575757;--canon-gray-6:#7b7b7b;--canon-gray-7:#9e9e9e;--canon-gray-8:#b4b4b4;--canon-bg:var(--canon-black);--canon-bg-surface-1:var(--canon-gray-1);--canon-bg-surface-2:var(--canon-gray-2);--canon-bg-solid:#9cc9ff;--canon-bg-solid-hover:#83b9fd;--canon-bg-solid-pressed:#83b9fd;--canon-bg-solid-disabled:#222;--canon-bg-tint:transparent;--canon-bg-tint-hover:#9cc9ff1f;--canon-bg-tint-pressed:#9cc9ff29;--canon-bg-tint-disabled:transparent;--canon-bg-danger:#3b1219;--canon-bg-warning:#302008;--canon-bg-success:#132d21;--canon-fg-primary:var(--canon-white);--canon-fg-secondary:var(--canon-gray-7);--canon-fg-link:#9cc9ff;--canon-fg-link-hover:#7eb5f7;--canon-fg-disabled:var(--canon-gray-7);--canon-fg-solid:#101821;--canon-fg-solid-disabled:var(--canon-gray-5);--canon-fg-tint:#9cc9ff;--canon-fg-tint-disabled:var(--canon-gray-5);--canon-fg-danger:#e22b2b;--canon-fg-warning:#e36d05;--canon-fg-success:#1db954;--canon-border:#fff3;--canon-border-hover:#fff6;--canon-border-pressed:#ffffff80;--canon-border-disabled:#fff3;--canon-border-danger:#f87a7a;--canon-border-warning:#e36d05;--canon-border-success:#53db83;--canon-ring:#1f5493;--canon-scrollbar:#3636363a;--canon-scrollbar-thumb:#575757}.canon-AvatarRoot{vertical-align:middle;user-select:none;color:var(--canon-fg-primary);background-color:var(--canon-bg-surface-2);border-radius:100%;justify-content:center;align-items:center;width:2rem;height:2rem;font-size:1rem;font-weight:500;line-height:1;display:inline-flex;overflow:hidden}.canon-AvatarRoot[data-size=small]{width:1.5rem;height:1.5rem}.canon-AvatarRoot[data-size=medium]{width:2rem;height:2rem}.canon-AvatarRoot[data-size=large]{width:3rem;height:3rem}.canon-AvatarImage{object-fit:cover;width:100%;height:100%}.canon-AvatarFallback{width:100%;height:100%;font-size:var(--canon-font-size-3);font-weight:var(--canon-font-weight-regular);box-shadow:inset 0 0 0 1px var(--canon-border);border-radius:var(--canon-radius-full);justify-content:center;align-items:center;display:flex}.canon-Box{font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-primary)}.canon-Button{user-select:none;font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-bold);cursor:pointer;border-radius:var(--canon-radius-2);justify-content:center;align-items:center;gap:var(--canon-space-1_5);border:none;padding:0;display:inline-flex;&:disabled{cursor:not-allowed}}.canon-Button[data-variant=primary]{background-color:var(--canon-bg-solid);color:var(--canon-fg-solid);transition:background-color .15s,box-shadow .15s;&:hover{background-color:var(--canon-bg-solid-hover)}&:active{background-color:var(--canon-bg-solid-pressed)}&:focus-visible{outline:2px solid var(--canon-ring);outline-offset:2px}&:disabled{background-color:var(--canon-bg-solid-disabled);color:var(--canon-fg-solid-disabled)}}.canon-Button[data-variant=secondary]{background-color:var(--canon-bg-surface-1);box-shadow:inset 0 0 0 1px var(--canon-border);color:var(--canon-fg-primary);transition:box-shadow .15s;&:hover{box-shadow:inset 0 0 0 1px var(--canon-border-hover)}&:active{box-shadow:inset 0 0 0 1px var(--canon-border-pressed)}&:focus-visible{box-shadow:inset 0 0 0 2px var(--canon-ring);outline:none;transition:none}&:disabled{box-shadow:inset 0 0 0 1px var(--canon-border-disabled);color:var(--canon-fg-disabled)}}.canon-Button[data-size=medium]{font-size:var(--canon-font-size-4);padding:0 var(--canon-space-3);height:2.5rem}.canon-Button[data-size=small]{font-size:var(--canon-font-size-3);padding:0 var(--canon-space-2);height:2rem}.canon-Button[data-size=small] svg{width:1rem;height:1rem}.canon-Button[data-size=medium] svg{width:1.25rem;height:1.25rem}.canon-ButtonIcon{justify-content:center;align-items:center}.canon-ButtonIcon[data-size=small]{width:2rem;padding:0}.canon-ButtonIcon[data-size=medium]{width:2.5rem;padding:0}.canon-CheckboxRoot{width:1rem;height:1rem;box-shadow:inset 0 0 0 1px var(--canon-border);cursor:pointer;background-color:var(--canon-bg-surface-1);border:none;border-radius:2px;flex-shrink:0;justify-content:center;align-items:center;padding:0;transition:background-color .2s ease-in-out;display:flex}.canon-CheckboxRoot:focus-visible{outline:2px solid var(--canon-ring);outline-offset:2px;transition:none}.canon-CheckboxRoot[data-checked]{background-color:var(--canon-bg-solid);box-shadow:none;color:var(--canon-fg-solid)}.canon-CheckboxLabel{align-items:center;gap:var(--canon-space-2);font-size:var(--canon-font-size-3);font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-primary);user-select:none;flex-direction:row;display:flex;&:hover{& .canon-CheckboxRoot:not([data-checked]){box-shadow:inset 0 0 0 1px var(--canon-border-hover)}}}.canon-CheckboxIndicator{color:var(--canon-fg-solid);justify-content:center;align-items:center;display:flex}.canon-CollapsiblePanel{height:var(--collapsible-panel-height);transition:all .15s ease-out;display:flex;overflow:hidden;&[data-starting-style],&[data-ending-style]{height:0}}.canon-Container{max-width:120rem;padding-inline:var(--canon-space-4);margin-inline:auto;transition:padding .2s ease-in-out}@media (width>=640px){.canon-Container{padding-inline:var(--canon-space-8)}}@media (width>=1024px){.canon-Container{padding-inline:var(--canon-space-12)}}.canon-DataTableRoot{gap:var(--canon-space-3);flex-direction:column;display:flex}.canon-DataTablePagination{padding-top:var(--canon-space-5);justify-content:space-between;align-items:center;display:flex}.canon-DataTablePagination--left{justify-content:space-between;align-items:center;display:flex}.canon-DataTablePagination--right{justify-content:space-between;align-items:center;gap:var(--canon-space-2);display:flex}.canon-DataTablePagination--select{min-width:10.5rem}.canon-FieldLabel{margin-bottom:var(--canon-space-3);gap:var(--canon-space-1);flex-direction:column;display:flex}.canon-FieldLabelLabel{color:var(--canon-fg-primary);cursor:pointer;font-weight:var(--canon-font-weight-regular);font-size:var(--canon-font-size-2);margin-right:auto}.canon-FieldLabelSecondaryLabel{color:var(--canon-fg-secondary);font-weight:var(--canon-font-weight-regular);margin-left:var(--canon-space-1)}.canon-FieldLabelDescription{font-weight:var(--canon-font-weight-regular);font-size:var(--canon-font-size-2);color:var(--canon-fg-secondary);margin:0}.canon-Flex{min-width:0;display:flex}.canon-Grid{display:grid}.canon-Heading{font-family:var(--canon-font-regular);color:var(--canon-fg-primary);margin:0;padding:0;line-height:100%}.canon-Heading[data-variant=display]{font-size:var(--canon-font-size-10);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-variant=title1]{font-size:var(--canon-font-size-9);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-variant=title2]{font-size:var(--canon-font-size-8);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-variant=title3]{font-size:var(--canon-font-size-7);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-variant=title4]{font-size:var(--canon-font-size-6);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-variant=title5]{font-size:var(--canon-font-size-5);font-weight:var(--canon-font-weight-bold)}.canon-Heading[data-color=primary]{color:var(--canon-fg-primary)}.canon-Heading[data-color=secondary]{color:var(--canon-fg-secondary)}.canon-Heading[data-truncate]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.canon-Icon{width:1rem;height:1rem}.canon-Link{font-family:var(--canon-font-regular);color:var(--canon-fg-link);cursor:pointer;margin:0;padding:0;text-decoration-line:none;&:hover{color:var(--canon-fg-link-hover);text-underline-offset:calc(.025em + 2px);text-decoration-line:underline;text-decoration-style:solid;text-decoration-thickness:min(2px,max(1px,.05em));text-decoration-color:color-mix(in srgb,var(--canon-fg-link-hover)30%,transparent)}}.canon-Link[data-variant=body]{font-size:var(--canon-font-size-3);line-height:140%}.canon-Link[data-variant=subtitle]{font-size:var(--canon-font-size-4);line-height:140%}.canon-Link[data-variant=caption]{font-size:var(--canon-font-size-2);line-height:140%}.canon-Link[data-variant=label]{font-size:var(--canon-font-size-1);line-height:140%}.canon-Link[data-weight=regular]{font-weight:var(--canon-font-weight-regular)}.canon-Link[data-weight=bold]{font-weight:var(--canon-font-weight-bold)}.canon-MenuPositioner{outline:0}.canon-MenuPopup{background-color:var(--canon-bg-surface-1);border:1px solid var(--canon-border);color:var(--canon-fg-primary);transform-origin:var(--transform-origin);max-width:min(var(--available-width),340px);max-height:min(var(--available-height),500px);padding-bottom:var(--canon-space-1);border-radius:.375rem;outline:none;flex-direction:column;transition:transform .15s,opacity .15s;display:flex;position:relative;overflow:auto;&[data-starting-style],&[data-ending-style]{opacity:0;transform:scale(.9)}}.canon-MenuItem{user-select:none;align-items:center;gap:var(--canon-space-2);height:32px;color:var(--canon-fg-primary);border-radius:var(--canon-radius-2);margin-inline:var(--canon-space-1);padding-inline:var(--canon-space-2);font-size:var(--canon-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;&:first-child{margin-top:var(--canon-space-1)}&[data-highlighted]{background-color:var(--canon-gray-3)}}.canon-MenuSubmenuTrigger{user-select:none;justify-content:space-between;align-items:center;gap:var(--canon-space-2);height:32px;color:var(--canon-fg-primary);border-radius:var(--canon-radius-2);margin-inline:var(--canon-space-1);padding-inline:var(--canon-space-2);font-size:var(--canon-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;& .canon-Icon{color:var(--canon-fg-secondary)}&:first-child{margin-top:var(--canon-space-1)}&[data-popup-open],&[data-highlighted]{background-color:var(--canon-gray-3);& .canon-Icon{color:var(--canon-fg-primary)}}}.canon-MenuSeparator{background-color:var(--color-gray-200);height:1px;margin:.375rem 1rem}.canon-SubmenuComboboxSearch{padding-inline:var(--canon-space-3);border:none;border-bottom:1px solid var(--canon-border);background-color:var(--canon-bg-surface-1);width:100%;height:32px;color:var(--canon-fg-primary);line-height:140%;font-size:var(--canon-font-size-3);z-index:1;outline:none;position:sticky;top:0;&::placeholder{color:var(--canon-fg-secondary)}&:disabled{opacity:.6;cursor:not-allowed}}.canon-SubmenuComboboxItems{padding-top:var(--canon-space-2);outline:none;flex-direction:column;display:flex;overflow-y:auto}.canon-SubmenuComboboxNoResults{padding-inline:var(--canon-space-3);padding-top:var(--canon-space-2);padding-bottom:var(--canon-space-4);color:var(--canon-fg-secondary);font-size:var(--canon-font-size-3)}.canon-SubmenuComboboxItem{user-select:none;justify-content:space-between;align-items:center;gap:var(--canon-space-2);height:32px;color:var(--canon-fg-primary);border-radius:var(--canon-radius-2);margin-inline:var(--canon-space-1);padding-inline:var(--canon-space-2);font-size:var(--canon-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;&[data-highlighted]{background-color:var(--canon-gray-3)}&[data-disabled]{opacity:.5;cursor:not-allowed}}.canon-SubmenuComboboxItemCheckbox{width:16px;height:16px;color:var(--canon-fg-primary);border-radius:var(--canon-radius-2);border:1px solid var(--canon-border);background:var(--canon-bg-surface-1);flex-shrink:0;justify-content:center;align-items:center;display:flex}.canon-SubmenuComboboxItemLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.canon-TableRoot{caption-side:bottom;border-collapse:collapse;width:100%}.canon-TableHead{text-align:left;padding:var(--canon-space-3);font-size:var(--canon-font-size-3);color:var(--canon-fg-primary)}.canon-TableBody{color:var(--canon-fg-primary)}.canon-TableRow{border-bottom:1px solid var(--canon-border);transition:color .2s ease-in-out}.canon-TableBody .canon-TableRow:hover{background-color:var(--canon-gray-2)}.canon-TableCell{padding:var(--canon-space-3);font-size:var(--canon-font-size-3)}.canon-TableCellText,.canon-TableCellLink{gap:var(--canon-space-0_5);flex-direction:column;display:flex}.canon-TableCellProfile{gap:var(--canon-space-2);flex-direction:row;align-items:center;display:flex}.canon-TableCellProfileAvatar{vertical-align:middle;user-select:none;color:var(--canon-fg-primary);background-color:var(--canon-bg-surface-2);border-radius:100%;justify-content:center;align-items:center;width:1.25rem;height:1.25rem;font-size:1rem;font-weight:500;line-height:1;display:inline-flex;overflow:hidden}.canon-TableCellProfileAvatarImage{object-fit:cover;width:100%;height:100%}.canon-TableCellProfileAvatarFallback{width:100%;height:100%;font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);box-shadow:inset 0 0 0 1px var(--canon-border);border-radius:var(--canon-radius-full);justify-content:center;align-items:center;display:flex}.canon-TabsRoot{border:1px solid var(--color-gray-200);border-radius:.375rem}.canon-TabsList{z-index:0;display:flex;position:relative}.canon-TabsTab{appearance:none;color:var(--canon-fg-secondary);user-select:none;padding-inline:var(--canon-space-3);height:2rem;font-family:inherit;font-size:.875rem;font-weight:500;line-height:1.25rem;font-size:var(--canon-font-size-2);cursor:pointer;background:0 0;border:0;outline:0;justify-content:center;align-items:center;margin:0;padding-block:0;transition:color .2s ease-in-out;display:flex;&[data-selected]{color:var(--canon-fg-primary)}@media (hover:hover){&:hover{color:var(--canon-fg-primary)}}&:focus-visible{position:relative;&:before{content:"";outline:1px solid var(--canon-ring);outline-offset:-1px;border-radius:.25rem;position:absolute;inset:.25rem 0}}}.canon-TabsIndicator{z-index:-1;translate:var(--active-tab-left)-50%;width:var(--active-tab-width);background-color:var(--canon-bg-solid);height:1px;transition-property:translate,width;transition-duration:.2s;transition-timing-function:ease-in-out;position:absolute;bottom:0;left:0}.canon-TabsPanel{&[hidden]{display:none}}.canon-Text{font-family:var(--canon-font-regular);margin:0;padding:0}.canon-Text[data-variant=body]{font-size:var(--canon-font-size-3);line-height:140%}.canon-Text[data-variant=subtitle]{font-size:var(--canon-font-size-4);line-height:140%}.canon-Text[data-variant=caption]{font-size:var(--canon-font-size-2);line-height:140%}.canon-Text[data-variant=label]{font-size:var(--canon-font-size-1);line-height:140%}.canon-Text[data-weight=regular]{font-weight:var(--canon-font-weight-regular)}.canon-Text[data-weight=bold]{font-weight:var(--canon-font-weight-bold)}.canon-Text[data-color=primary]{color:var(--canon-fg-primary)}.canon-Text[data-color=secondary]{color:var(--canon-fg-secondary)}.canon-Text[data-color=danger]{color:var(--canon-fg-danger)}.canon-Text[data-color=warning]{color:var(--canon-fg-warning)}.canon-Text[data-color=success]{color:var(--canon-fg-success)}.canon-Text[data-truncate]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.canon-TextField{font-family:var(--canon-font-regular);flex-direction:column;width:100%;display:flex}.canon-TextFieldInputWrapper{position:relative}.canon-TextFieldInputWrapper[data-size=small]{height:2rem}.canon-TextFieldInputWrapper[data-size=medium]{height:2.5rem}.canon-TextFieldIcon{left:var(--canon-space-3);margin-right:var(--canon-space-1);color:var(--canon-fg-primary);flex-shrink:0;position:absolute;top:50%;transform:translateY(-50%)}.canon-TextFieldIcon[data-size=small],.canon-TextFieldIcon[data-size=small] svg{width:1rem;height:1rem}.canon-TextFieldIcon[data-size=medium],.canon-TextFieldIcon[data-size=medium] svg{width:1.25rem;height:1.25rem}.canon-TextFieldInput{padding:0 var(--canon-space-3);border-radius:var(--canon-radius-3);border:1px solid var(--canon-border);background-color:var(--canon-bg-surface-1);font-size:var(--canon-font-size-3);font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-primary);width:100%;height:100%;cursor:inherit;align-items:center;transition:border-color .2s ease-in-out,outline-color .2s ease-in-out;display:flex}.canon-TextFieldInput::placeholder{color:var(--canon-fg-secondary)}.canon-TextFieldInput[data-icon]{padding-left:var(--canon-space-8)}.canon-TextFieldInput[data-focused]{outline-color:var(--canon-border-pressed);outline-width:0}.canon-TextFieldInput[data-hovered]{border-color:var(--canon-border-hover)}.canon-TextFieldInput[data-focused]{border-color:var(--canon-border-pressed);outline-width:0}.canon-TextFieldInput[data-invalid]{border-color:var(--canon-fg-danger)}.canon-TextFieldInput[data-disabled]{opacity:.5;cursor:not-allowed;border:1px solid var(--canon-border-disabled)}.canon-TextFieldError{color:var(--canon-fg-danger);font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);margin-top:var(--canon-space-2)}.canon-TooltipPopup{box-sizing:border-box;transform-origin:var(--transform-origin);background-color:canvas;background-color:var(--canon-bg-surface-1);color:var(--canon-fg-primary);outline:1px solid var(--canon-border);box-shadow:0 10px 15px -3px var(--canon-border),0 4px 6px -4px var(--canon-border);border-radius:.375rem;flex-direction:column;padding:.25rem .5rem;font-size:.875rem;line-height:1.25rem;transition:transform .15s,opacity .15s;display:flex;&[data-starting-style],&[data-ending-style]{opacity:0;transform:scale(.9)}&[data-instant]{transition-duration:0s}}.canon-TooltipArrow{display:flex;&[data-side=top]{bottom:-8px;rotate:180deg}&[data-side=bottom]{top:-8px;rotate:none}&[data-side=left]{right:-13px;rotate:90deg}&[data-side=right]{left:-13px;rotate:-90deg}}.canon-TooltipArrow-fill{fill:var(--canon-bg-surface-1)}.canon-TooltipArrow-outer-stroke{@media (prefers-color-scheme:light){fill:var(--canon-border)}}.canon-ScrollAreaRoot{box-sizing:border-box;width:24rem;max-width:calc(100vw - 8rem);height:8.5rem}.canon-ScrollAreaViewport{overscroll-behavior:contain;height:100%}.canon-ScrollAreaContent{padding-block:.75rem;flex-direction:column;gap:1rem;padding-left:1rem;padding-right:1.5rem;display:flex}.canon-ScrollAreaScrollbar{background-color:var(--canon-scrollbar);opacity:0;border-radius:.375rem;justify-content:center;width:.25rem;margin:.5rem;transition:opacity .15s .3s;display:flex;&[data-hovering],&[data-scrolling]{opacity:1;transition-duration:75ms;transition-delay:0s}&:before{content:"";width:1.25rem;height:100%;position:absolute}}.canon-ScrollAreaThumb{border-radius:inherit;background-color:var(--canon-scrollbar-thumb);width:100%}.canon-Select{font-family:var(--canon-font-regular);flex-direction:column;width:100%;display:flex}.canon-SelectLabel{font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-primary);margin-bottom:var(--canon-space-1_5);cursor:pointer}.canon-SelectLabel[data-disabled]{cursor:default}.canon-SelectDescription{font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-secondary);padding-top:var(--canon-space-1_5);margin:0}.canon-SelectError{font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-danger);padding-top:var(--canon-space-1_5);margin:0}.canon-SelectTrigger{box-sizing:border-box;border-radius:var(--canon-radius-3);border:1px solid var(--canon-border);padding:0 var(--canon-space-4);background-color:var(--canon-bg-surface-1);font-size:var(--canon-font-size-3);font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-regular);color:var(--canon-fg-primary);cursor:pointer;justify-content:space-between;align-items:center;gap:var(--canon-space-2);width:100%;transition:border-color .2s ease-in-out,outline-color .2s ease-in-out;display:flex}.canon-SelectTrigger::placeholder{color:var(--canon-fg-secondary)}.canon-SelectTrigger:hover{border-color:var(--canon-border-hover)}.canon-SelectTrigger:focus-visible{border-color:var(--canon-border-pressed);outline:0}.canon-SelectTrigger[data-invalid]{border-color:var(--canon-fg-danger)}.canon-SelectTrigger[data-invalid]:hover,.canon-SelectTrigger[data-invalid]:focus-visible{border-width:2px}.canon-SelectTrigger[data-disabled]{cursor:not-allowed;border-color:var(--canon-border-disabled);color:var(--canon-fg-disabled)}.canon-SelectTrigger[data-size=small]{height:2rem}.canon-SelectTrigger[data-size=medium]{height:3rem}.canon-SelectIcon{margin-left:var(--canon-space-5);transition:transform .2s}.canon-SelectTrigger[data-popup-open] .canon-SelectIcon{transform:rotate(180deg)}.canon-SelectPopup{box-sizing:border-box;max-height:var(--available-height);background-color:var(--canon-bg-surface-1);border:1px solid var(--canon-border);border-radius:var(--canon-radius-3);padding-block:var(--canon-space-1);z-index:1;transform-origin:var(--transform-origin);outline:0;transition:transform .15s,opacity .15s;overflow-y:auto;box-shadow:0 4px 12px #0003}.canon-SelectPopup[data-starting-style],.canon-SelectPopup[data-ending-style]{opacity:0;transform:scale(.9)}.canon-SelectItem{width:var(--anchor-width);padding-block:var(--canon-space-2);padding-inline:var(--canon-space-4);color:var(--canon-fg-primary);border-radius:var(--canon-radius-3);cursor:pointer;user-select:none;font-size:var(--canon-font-size-3);align-items:center;gap:var(--canon-space-2);outline:none;grid-template-columns:1rem 1fr;grid-template-areas:"icon text";display:grid;position:relative}.canon-SelectItem[data-highlighted]{z-index:0;color:var(--canon-fg-primary);position:relative}.canon-SelectItem[data-highlighted]:before{content:"";z-index:-1;background-color:var(--canon-bg-tint-hover);border-radius:.25rem;position:absolute;inset-block:0;inset-inline:.25rem}.canon-SelectItem[data-disabled]{cursor:not-allowed;color:var(--canon-fg-disabled)}.canon-SelectItemIndicator{grid-area:icon;justify-content:center;align-items:center;display:flex}.canon-SelectItemText{flex:1;grid-area:text}.canon-SelectRequired{color:var(--canon-fg-secondary);font-size:var(--canon-font-size-2);font-weight:var(--canon-font-weight-regular);margin-left:var(--canon-space-1)}.canon-SelectIcon{justify-content:center;align-items:center;display:flex}.canon-SelectValue{text-overflow:ellipsis;white-space:nowrap;width:100%;overflow:hidden}.canon-Switch{align-items:center;gap:var(--canon-space-3);font-size:var(--canon-font-size-3);color:var(--canon-fg-primary);cursor:pointer;display:flex;position:relative;&[data-pressed] .canon-SwitchIndicator{&:before{background:var(--canon-fg-solid)}}&[data-selected]{& .canon-SwitchIndicator{background:var(--canon-bg-solid);&:before{background:var(--canon-fg-solid);transform:translate(100%)}}&[data-pressed]{& .indicator{background:var(--canon-gray-3)}}}&[data-focus-visible] .canon-SwitchIndicator{outline-offset:2px;outline:2px solid}}.canon-SwitchIndicator{background:var(--canon-gray-3);border:2px;border-radius:1.143rem;width:2rem;height:1.143rem;transition:all .2s;&:before{content:"";background:var(--canon-fg-solid);border-radius:16px;width:.857rem;height:.857rem;margin:.143rem;transition:all .2s;display:block}} \ No newline at end of file diff --git a/canon-docs/scripts/build-css.js b/canon-docs/scripts/build-css.js deleted file mode 100644 index edd80add51..0000000000 --- a/canon-docs/scripts/build-css.js +++ /dev/null @@ -1,34 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const { bundle } = require('lightningcss'); - -const source = '../../packages/canon/src/css'; -const destination = '../public'; - -const source1 = path.join(__dirname, `${source}/styles.css`); -const destination1 = path.join(__dirname, `${destination}/styles.css`); - -// Function to bundle and copy the CSS file -const bundleAndCopyFile = async (source, destination) => { - try { - const result = await bundle({ - filename: source, - minify: true, - }); - - fs.writeFileSync(destination, result.code); - console.log('File bundled and copied successfully!'); - } catch (err) { - console.error('Error bundling file:', err); - } -}; - -// Initial bundle and copy -Promise.all([bundleAndCopyFile(source1, destination1)]) - .then(() => { - // Add an empty line after all operations are complete - It looks better in the terminal :) - console.log(''); - }) - .catch(err => { - console.error('Error in processing files:', err); - }); diff --git a/canon-docs/src/app/(docs)/layout.module.css b/canon-docs/src/app/(docs)/layout.module.css deleted file mode 100644 index fa94ef3a13..0000000000 --- a/canon-docs/src/app/(docs)/layout.module.css +++ /dev/null @@ -1,6 +0,0 @@ -.pageContainer { - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 24px 64px; -} diff --git a/canon-docs/src/app/(docs)/layout.tsx b/canon-docs/src/app/(docs)/layout.tsx deleted file mode 100644 index 161523bbf5..0000000000 --- a/canon-docs/src/app/(docs)/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { Metadata } from 'next'; - -import styles from './layout.module.css'; - -export const metadata: Metadata = { - title: 'Canon', - description: 'UI library for Backstage', -}; - -export default function DocsLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return
{children}
; -} diff --git a/canon-docs/src/app/(playground)/playground/page.tsx b/canon-docs/src/app/(playground)/playground/page.tsx deleted file mode 100644 index e2ad294633..0000000000 --- a/canon-docs/src/app/(playground)/playground/page.tsx +++ /dev/null @@ -1,87 +0,0 @@ -'use client'; - -import { ReactNode } from 'react'; -import { Grid, Flex, Text } from '../../../../../packages/canon'; -import { screenSizes } from '@/utils/data'; -import { Frame } from '@/components/Frame'; -import { usePlayground } from '@/utils/playground-context'; -import { - ButtonSnippet, - CheckboxSnippet, - HeadingSnippet, - TextSnippet, -} from '@/snippets/stories-snippets'; - -import styles from './styles.module.css'; - -export default function PlaygroundPage() { - const { selectedScreenSizes } = usePlayground(); - - const filteredScreenSizes = screenSizes.filter(item => - selectedScreenSizes.includes(item.slug), - ); - - if (filteredScreenSizes.length === 0) { - return ( -
- -
- ); - } - - return ( -
- {filteredScreenSizes.map(screenSize => ( -
- - {screenSize.title} - {screenSize.width}px - -
- - - -
-
- ))} -
- ); -} - -const Content = () => { - const { selectedComponents } = usePlayground(); - - return ( - - {selectedComponents.find(c => c === 'button') && ( - } title="Button" /> - )} - {selectedComponents.find(c => c === 'checkbox') && ( - } - title="Checkbox" - /> - )} - {selectedComponents.find(c => c === 'heading') && ( - } title="Heading" /> - )} - {selectedComponents.find(c => c === 'text') && ( - } title="Text" /> - )} - - ); -}; - -const Line = ({ content, title }: { content: ReactNode; title: string }) => { - return ( - - - {title} - - {content} - - ); -}; diff --git a/canon-docs/src/app/(playground)/playground/styles.module.css b/canon-docs/src/app/(playground)/playground/styles.module.css deleted file mode 100644 index 026e8a1bd4..0000000000 --- a/canon-docs/src/app/(playground)/playground/styles.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.container { - height: 100vh; - display: flex; - flex-direction: row; - gap: 24px; - overflow-x: scroll; -} - -.containerEmpty { - padding: 78px 40px; -} - -.breakpointContainer { - flex-shrink: 0; - margin-top: 40px; - height: calc(100vh - 86px); - display: flex; - flex-direction: column; - gap: 8px; - - &:first-child { - margin-left: 48px; - } - - &:last-child { - margin-right: 48px; - } -} - -.breakpointContent { - height: 100%; - border-radius: 4px; - border: 1px solid var(--border); - background-color: var(--bg); - padding: 16px; -} diff --git a/canon-docs/src/app/layout.tsx b/canon-docs/src/app/layout.tsx deleted file mode 100644 index b32622e4ae..0000000000 --- a/canon-docs/src/app/layout.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { Metadata } from 'next'; -import { Sidebar } from '../components/Sidebar'; -import { Toolbar } from '@/components/Toolbar'; -import { Providers } from './providers'; -import { CustomTheme } from '@/components/CustomTheme'; -import styles from '../css/page.module.css'; - -import '../css/globals.css'; -import '/public/core.css'; -import '/public/components.css'; - -export const metadata: Metadata = { - title: 'Canon', - description: 'UI library for Backstage', - metadataBase: new URL('https://canon.backstage.io'), -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - -
- -
- - {children} -
- -
-
- - - ); -} diff --git a/canon-docs/src/components/Changelog/index.tsx b/canon-docs/src/components/Changelog/index.tsx deleted file mode 100644 index e43c662be5..0000000000 --- a/canon-docs/src/components/Changelog/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { changelog } from '@/utils/changelog'; -import { MDXRemote } from 'next-mdx-remote-client/rsc'; -import { formattedMDXComponents } from '@/mdx-components'; - -export function Changelog() { - // Group changelog entries by version - const groupedChangelog = changelog.reduce((acc, entry) => { - if (!acc[entry.version]) { - acc[entry.version] = []; - } - acc[entry.version].push(entry); - return acc; - }, {} as Record); - - // Sort versions in descending order - const sortedVersions = Object.keys(groupedChangelog).sort((a, b) => - b.localeCompare(a), - ); - - const content = sortedVersions - .map(version => { - const entries = groupedChangelog[version]; - - return `## Version ${version} - - ${entries - .map(e => { - const prs = - e.prs.length > 0 && - e.prs - .map( - pr => - `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, - ) - .join(', '); - return `- ${e.description} ${prs}`; - }) - .join('\n')}`; - }) - .join('\n'); - - return ; -} diff --git a/canon-docs/src/components/ComponentInfos/ComponentInfos.tsx b/canon-docs/src/components/ComponentInfos/ComponentInfos.tsx deleted file mode 100644 index a29b01cba0..0000000000 --- a/canon-docs/src/components/ComponentInfos/ComponentInfos.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import type { ComponentInfosProps } from './types'; -import styles from '@/css/mdx.module.css'; -import Link from 'next/link'; -import { changelog } from '@/utils/changelog'; -import { MDXRemote } from 'next-mdx-remote-client/rsc'; -import { formattedMDXComponents } from '@/mdx-components'; - -export const ComponentInfos = ({ - usageCode, - component, - classNames, -}: ComponentInfosProps) => { - const componentChangelog = changelog.filter(c => - c.components.includes(component), - ); - - return ( - - - Usage - {classNames && classNames.length > 0 && Theming} - Changelog - - - - - {classNames && classNames.length > 0 && ( - -

- We recommend starting with our{' '} - - global tokens - {' '} - to customize the library and align it with your brand. For - additional flexibility, you can use the provided class names for - each element listed below. -

- `- \`${className}\``) - .join('\n')}`} - /> -
- )} - - { - const prs = - change.prs.length > 0 && - change.prs - .map( - pr => - `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, - ) - .join(', '); - return `- \`${change.version}\` - ${change.description} ${prs}`; - }) - .join('\n')}`} - /> - -
- ); -}; diff --git a/canon-docs/src/components/ComponentInfos/index.ts b/canon-docs/src/components/ComponentInfos/index.ts deleted file mode 100644 index 04dbaeb1c6..0000000000 --- a/canon-docs/src/components/ComponentInfos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ComponentInfos } from './ComponentInfos'; diff --git a/canon-docs/src/components/ComponentInfos/types.ts b/canon-docs/src/components/ComponentInfos/types.ts deleted file mode 100644 index 8814ff479a..0000000000 --- a/canon-docs/src/components/ComponentInfos/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Component } from '@/utils/changelog'; -import { ReactNode } from 'react'; - -export interface ComponentInfosProps { - usageCode?: string; - classNames?: string[]; - component: Component; - children: ReactNode; -} diff --git a/canon-docs/src/components/Frame/index.tsx b/canon-docs/src/components/Frame/index.tsx deleted file mode 100644 index d6255401dd..0000000000 --- a/canon-docs/src/components/Frame/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import ReactFrame from 'react-frame-component'; - -export const Frame = ({ children }: { children: React.ReactNode }) => { - const [show, setShow] = useState(false); - - useEffect(() => { - setShow(true); - }, []); - - if (!show) return null; - - return ( -
`} - mountTarget=".frame-root" - head={ - <> - - - - - } - > - {children} -
- ); -}; diff --git a/canon-docs/src/components/Sidebar/docs.tsx b/canon-docs/src/components/Sidebar/docs.tsx deleted file mode 100644 index da501b151a..0000000000 --- a/canon-docs/src/components/Sidebar/docs.tsx +++ /dev/null @@ -1,82 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { components, overview, layoutComponents, theme } from '@/utils/data'; -import { motion } from 'motion/react'; -import styles from './Sidebar.module.css'; -import { usePathname } from 'next/navigation'; -import { Fragment } from 'react'; - -const data = [ - { - title: 'Overview', - content: overview, - url: '', - }, - { - title: 'Theme', - content: theme, - url: '/theme', - }, - { - title: 'Layout Components', - content: layoutComponents, - url: '/components', - }, - { - title: 'Components', - content: components, - url: '/components', - }, -]; - -export const Docs = () => { - const pathname = usePathname(); - const isPlayground = pathname.includes('/playground'); - - return ( - - {data.map(section => { - return ( - -
{section.title}
- - {section.content.map(item => { - const isActive = pathname === `${section.url}/${item.slug}`; - - return ( - -
{item.title}
-
- {item.status === 'alpha' && 'Alpha'} - {item.status === 'beta' && 'Beta'} - {item.status === 'inProgress' && 'In Progress'} - {item.status === 'stable' && 'Stable'} - {item.status === 'deprecated' && 'Deprecated'} -
- - ); - })} -
- ); - })} -
- ); -}; diff --git a/canon-docs/src/components/Sidebar/index.tsx b/canon-docs/src/components/Sidebar/index.tsx deleted file mode 100644 index ad6df68b97..0000000000 --- a/canon-docs/src/components/Sidebar/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import styles from './Sidebar.module.css'; -import { Docs } from './docs'; -import { Playground } from './playground'; -import Link from 'next/link'; -import { ScrollArea } from '@base-ui-components/react/scroll-area'; - -export const Sidebar = () => { - return ( -
- - -
-
- - - - - - -
-
- - -
-
-
- - - -
-
- ); -}; diff --git a/canon-docs/src/components/Sidebar/playground.tsx b/canon-docs/src/components/Sidebar/playground.tsx deleted file mode 100644 index 2aaa4fe2c6..0000000000 --- a/canon-docs/src/components/Sidebar/playground.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client'; - -import { components } from '@/utils/data'; -import { Checkbox } from '@backstage/canon'; -import { motion } from 'motion/react'; -import styles from './Sidebar.module.css'; -import { usePathname } from 'next/navigation'; -import { screenSizes } from '@/utils/data'; -import { usePlayground } from '@/utils/playground-context'; - -export const Playground = () => { - const pathname = usePathname(); - const isPlayground = pathname.includes('/playground'); - const { - selectedScreenSizes, - setSelectedScreenSizes, - selectedComponents, - setSelectedComponents, - } = usePlayground(); - - const handleComponentCheckboxChange = (slug: string) => { - if (selectedComponents.find(item => item === slug)) { - const res = selectedComponents.filter(item => item !== slug); - setSelectedComponents(res); - } else { - setSelectedComponents([...selectedComponents, slug]); - } - }; - - const handleCheckboxChange = (slug: string) => { - if (selectedScreenSizes.find(item => item === slug)) { - const res = selectedScreenSizes.filter(item => item !== slug); - setSelectedScreenSizes(res); - } else { - setSelectedScreenSizes([...selectedScreenSizes, slug]); - } - }; - - return ( - -
Components
- {components.map(({ slug, title }) => ( -
-
{title}
- handleComponentCheckboxChange(slug)} - /> -
- ))} -
Screen sizes
- {screenSizes.map(({ slug, title }) => ( -
-
{title}
- handleCheckboxChange(slug)} - /> -
- ))} -
- ); -}; diff --git a/canon-docs/src/components/Tabs/styles.module.css b/canon-docs/src/components/Tabs/styles.module.css deleted file mode 100644 index 82e744b8b2..0000000000 --- a/canon-docs/src/components/Tabs/styles.module.css +++ /dev/null @@ -1,27 +0,0 @@ -.root { - margin-top: 40px; -} - -.list { - display: flex; - gap: var(--canon-space-6); - border-bottom: 1px solid var(--border); - position: relative; - margin-bottom: var(--canon-space-6); -} - -.tab { - all: unset; - cursor: pointer; - padding-bottom: 8px; -} - -.indicator { - position: absolute; - bottom: -1px; - left: var(--active-tab-left); - width: var(--active-tab-width); - height: 1px; - background-color: var(--primary); - transition: all 0.2s ease-in-out; -} diff --git a/canon-docs/src/components/Toolbar/index.tsx b/canon-docs/src/components/Toolbar/index.tsx deleted file mode 100644 index eac51f1857..0000000000 --- a/canon-docs/src/components/Toolbar/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ThemeSelector } from './theme'; -import { ThemeNameSelector } from './theme-name'; -import styles from './styles.module.css'; -import { Nav } from './nav'; - -export const Toolbar = () => { - return ( -
-
-
-
- - -
-
- ); -}; diff --git a/canon-docs/src/components/Toolbar/nav.module.css b/canon-docs/src/components/Toolbar/nav.module.css deleted file mode 100644 index 95228fa917..0000000000 --- a/canon-docs/src/components/Toolbar/nav.module.css +++ /dev/null @@ -1,78 +0,0 @@ -.tabs { - display: none; -} - -@media (min-width: 768px) { - .tabs { - display: block; - height: 60px; - } -} - -.tabsTheme { - width: 142px; - border-radius: 0.375rem; - background-color: var(--bg); - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; -} - -.list { - display: flex; - position: relative; - z-index: 0; - gap: var(--canon-space-8); -} - -.tab { - all: unset; - height: 60px; - color: var(--secondary); - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-bold); - cursor: pointer; - transition: color 0.2s ease-in-out; - - &:hover { - color: var(--primary); - } - - &[data-selected] { - color: var(--primary); - - & p { - color: var(--primary); - } - } - - &:focus-visible { - position: relative; - - &::before { - content: ''; - position: absolute; - inset: 0.25rem 0; - border-radius: 0.25rem; - outline: 2px solid var(--panel); - outline-offset: -1px; - } - } -} - -.tab p { - color: var(--secondary) !important; -} - -.indicator { - position: absolute; - z-index: -1; - left: 0; - bottom: -1px; - translate: var(--active-tab-left) -50%; - width: var(--active-tab-width); - height: 1px; - border-radius: 0.25rem; - background-color: var(--primary); - transition-property: translate, width, background-color; - transition-duration: 200ms; - transition-timing-function: ease-in-out; -} diff --git a/canon-docs/src/components/Toolbar/nav.tsx b/canon-docs/src/components/Toolbar/nav.tsx deleted file mode 100644 index 017599581e..0000000000 --- a/canon-docs/src/components/Toolbar/nav.tsx +++ /dev/null @@ -1,49 +0,0 @@ -'use client'; - -import { Tabs } from '@base-ui-components/react/tabs'; -import { usePathname } from 'next/navigation'; -import { useRouter } from 'next/navigation'; -import styles from './nav.module.css'; - -export const Nav = () => { - const pathname = usePathname(); - const router = useRouter(); - - const onValueChange = (value: string) => { - if (value === 'docs') { - router.push('/'); - } else { - router.push('/playground'); - } - }; - - return ( - - - { - router.push('/'); - }} - > - Documentation - - { - router.push('/playground'); - }} - > - Playground - - - - - ); -}; diff --git a/canon-docs/src/components/Toolbar/styles.module.css b/canon-docs/src/components/Toolbar/styles.module.css deleted file mode 100644 index 5379e2047c..0000000000 --- a/canon-docs/src/components/Toolbar/styles.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.toolbar { - position: sticky; - top: 16px; - left: 0; - right: 0; - border-radius: 8px; - z-index: 10; - background-color: var(--panel); - height: 60px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 var(--canon-space-6); - transition: background-color 0.2s ease-in-out; - box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025); - border: 1px solid var(--border); -} - -.actions { - display: flex; - align-items: center; - gap: var(--canon-space-4); -} diff --git a/canon-docs/src/content/components/heading.mdx b/canon-docs/src/content/components/heading.mdx deleted file mode 100644 index 9d746d41b0..0000000000 --- a/canon-docs/src/content/components/heading.mdx +++ /dev/null @@ -1,66 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { HeadingSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; -import { CodeBlock } from '@/components/CodeBlock'; -import { - headingPropDefs, - headingUsageSnippet, - headingDefaultSnippet, - headingVariantsSnippet, - headingTruncateSnippet, - headingResponsiveSnippet, -} from './heading.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; - -# Heading - -Headings are used to structure the content of your page. - -} - code={headingDefaultSnippet} -/> - - - -## API reference - - - -## Examples - -### All variants - -The `Heading` component has a `variant` prop that can be used to change the -appearance of the heading. - -} - code={headingVariantsSnippet} -/> - -### Truncate - -The `Heading` component has a `truncate` prop that can be used to truncate the -heading. - -} - code={headingTruncateSnippet} -/> - -### Responsive - -You can also use the `variant` prop to change the appearance of the text based -on the screen size. - - diff --git a/canon-docs/src/content/components/heading.props.ts b/canon-docs/src/content/components/heading.props.ts deleted file mode 100644 index 132782c6b9..0000000000 --- a/canon-docs/src/content/components/heading.props.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - classNamePropDefs, - stylePropDefs, - type PropDef, -} from '@/utils/propDefs'; - -export const headingPropDefs: Record = { - variant: { - type: 'enum', - values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'], - responsive: true, - }, - children: { - type: 'enum', - values: ['ReactNode'], - responsive: false, - }, - truncate: { - type: 'boolean', - default: 'false', - }, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const headingUsageSnippet = `import { Heading } from '@backstage/canon'; - -`; - -export const headingDefaultSnippet = `Hello World!`; - -export const headingVariantsSnippet = ` - Display - Title 1 - Title 2 - Title 3 - Title 4 -`; - -export const headingTruncateSnippet = ` - 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 headingResponsiveSnippet = ` - Responsive heading -`; diff --git a/canon-docs/src/content/components/link.mdx b/canon-docs/src/content/components/link.mdx deleted file mode 100644 index 96c7fa0816..0000000000 --- a/canon-docs/src/content/components/link.mdx +++ /dev/null @@ -1,71 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { CodeBlock } from '@/components/CodeBlock'; -import { - MenuSnippet, - ButtonSnippet, - LinkSnippet, -} from '@/snippets/stories-snippets'; -import { - linkPropDefs, - linkUsageSnippet, - linkDefaultSnippet, - linkVariantsSnippet, - linkWeightsSnippet, -} from './link.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; - -# Link - -A link component that renders a `` element. - -} - code={linkDefaultSnippet} -/> - - - -## API reference - - - -## Examples - -### Variants - -Here's a view when links have different variants. - -} - code={linkVariantsSnippet} -/> - -### Weights - -Here's a view when links have different weights. - -} - code={linkWeightsSnippet} -/> diff --git a/canon-docs/src/content/components/link.props.ts b/canon-docs/src/content/components/link.props.ts deleted file mode 100644 index 65c72b20e4..0000000000 --- a/canon-docs/src/content/components/link.props.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - classNamePropDefs, - stylePropDefs, - type PropDef, -} from '@/utils/propDefs'; - -export const linkPropDefs: Record = { - to: { - type: 'string', - }, - variant: { - type: 'enum', - values: ['subtitle', 'body', 'caption', 'label'], - default: 'body', - responsive: true, - }, - weight: { - type: 'enum', - values: ['regular', 'bold'], - default: 'regular', - responsive: true, - }, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const linkUsageSnippet = `import { Link } from '@backstage/canon'; - -Sign up for Backstage`; - -export const linkDefaultSnippet = `Sign up for Backstage`; - -export const linkVariantsSnippet = ` - - - - -`; - -export const linkWeightsSnippet = ` - - -`; diff --git a/canon-docs/src/content/components/table.mdx b/canon-docs/src/content/components/table.mdx deleted file mode 100644 index f169bcd7f9..0000000000 --- a/canon-docs/src/content/components/table.mdx +++ /dev/null @@ -1 +0,0 @@ -# Table (Coming soon) diff --git a/canon-docs/src/content/components/text.props.ts b/canon-docs/src/content/components/text.props.ts deleted file mode 100644 index 00dc494c96..0000000000 --- a/canon-docs/src/content/components/text.props.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { - childrenPropDefs, - classNamePropDefs, - stylePropDefs, -} from '@/utils/propDefs'; -import type { PropDef } from '@/utils/propDefs'; - -export const textPropDefs: Record = { - variant: { - type: 'enum', - values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'], - responsive: true, - }, - weight: { - type: 'enum', - values: ['regular', 'bold'], - responsive: true, - }, - truncate: { - type: 'boolean', - default: 'false', - }, - ...childrenPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const textUsageSnippet = `import { Text } from '@backstage/canon'; - -`; - -export const textDefaultSnippet = ` - 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 textVariantsSnippet = ` - - 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? - - - 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? - - - 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? - - - 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 textWeightsSnippet = ` - - 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? - - - 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 textTruncateSnippet = ` - 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 textResponsiveSnippet = ` - Responsive text -`; diff --git a/canon-docs/src/css/page.module.css b/canon-docs/src/css/page.module.css deleted file mode 100644 index 3a0bb492d8..0000000000 --- a/canon-docs/src/css/page.module.css +++ /dev/null @@ -1,50 +0,0 @@ -.global { - width: 100%; -} - -.container { - width: 100%; - padding: 0 16px; -} - -@media (min-width: 768px) { - .container { - padding-left: 332px; - } -} - -.page { - flex: 1; -} - -.page p { - color: var(--primary); - font-size: 1rem; - line-height: 1.5rem; - margin-top: 0; - margin-bottom: 1rem; -} - -.content { - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 64px 24px 64px; -} - -.header { - width: 100%; - margin-bottom: 64px; -} - -.header img { - width: 100%; - height: auto; -} - -.pageContainer { - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 24px 64px; -} diff --git a/contrib/catalog/read-write-split/README.md b/contrib/catalog/read-write-split/README.md new file mode 100644 index 0000000000..4a99ebe076 --- /dev/null +++ b/contrib/catalog/read-write-split/README.md @@ -0,0 +1,85 @@ +# Catalog Read-Write Split + +This article gives an overview of how you might split your catalog deployment into two - one which handles only reads (the read part of the API), and another that handles everything else (the write part of the API, and processing and ingestion etc). + +This is useful for several reasons: + +- The performance characteristics and scaling needs of those two concerns typically differ significantly +- Moving the bursty processing and ingestion load on a separate deployment can make the important read part of the API have more deterministic response times +- It opens up for easier cross region deployment of read nodes, while having write nodes in a single "home" region +- It also opens up for primary/secondary split of the underlying database, with streaming replication + +## Overview + +This is a rough overview of what we will go through: + +- Ensure that all frontend code uses `catalogApiRef`, and all backend code uses `catalogServiceRef`, for talking to the catalog +- Add a separate discovery name for the write deployment +- Register both frontend and backend implementations of the catalog client that know to send traffic to the right discovery name as needed +- Set up the backend itself with dedicated read and write configuration +- Split the deployment into two +- Follow up with a database split, if desired + +## 1. Prerequisite: Establish usage of catalog client refs + +First, ensure that all of your code uses _injected_ catalog clients for its catalog communications needs instead of making their own with `new`. For frontend code that means leveraging `catalogApiRef`, and for backend it means leveraging `catalogServiceRef`. This is what enables the sort of wholesale injection of custom behaviors that we are about to do, and is a strongly recommended best practice either way. + +- ✅ Search through your projects and ensure that there are no `new CatalogClient` calls. If you find any, consider rewriting that code to instead having the client injected through leveraging the corresponding ref. + +- ✅ Search through your projects and ensure that you do _not_ import the `catalogServiceRef` that specifically is in the `@backstage/plugin-catalog-node/alpha` export. That one has been deprecated for a long time and will not be targeted by this guide. If you find any, consider rewriting that code to instead inject the client from `@backstage/plugin-catalog-node` (note the lack of `/alpha`). + +> [!TIP] +> If you find usages of `new CatalogClient` in tests, you can normally leave those as-is. You can however consider to later try out the `catalogApiMock` from `@backstage/plugin-catalog-react/testUtils` for frontend tests, and `catalogServiceMock` from `@backstage/plugin-catalog-node/testUtils` for backend tests. These allow you to inject a client that behaves like a complete fake catalog backend with entities in it, without complex mocking. + +## 2. Decide your deployment split structure + +We will be defining a fake plugin ID called `catalog-write`. In addition to your current single catalog deployment you will add a second one that receives traffic for `catalog-write`. You need to decide upon what your ingress to those two deployments will look like. This is highly company dependent, so we cannot give general guidance. + +This guide will however NOT split the code base into two. It will instead change your catalog backend code in such a way that it can support either deployment. This is all very flexible and you can tweak it as you see fit, but that's what worked well for us. + +This guide will assume that when all is said and done, requests for the `catalog` plugin ID resolve to the URL `https://catalog-read.example.net/api/catalog`, and requests for the `catalog-write` plugin ID resolve to the URL `https://catalog-write.example.net/api/catalog`. This is just for illustration and you shall change these to their actual correct values at your company. + +- ✅ Copy the contents of [the `app-config.yaml` file](./workspace/app-config.yaml) to your own. We will assume that these exact settings are applied both to your frontend and your catalog (read AND write) deployment. For now, if you are applying this guide step by step rather than all at once, you can set the URLs in there to point to your good old pre-split deployment and only update them again after the split. + +> [!TIP] +> As a future refactor, you could instead break out this behavior into a custom injected discovery implementation in a library that all your projects can import. That takes a few more steps and is left as a separate exercise. If you already have such a library in your internal NPM, feel free to put it there to begin with and import from there. + +## 3. Get split-aware catalog clients in place + +Now let's put clients in place whose methods send traffic to either `catalog` or `catalog-write` as needed. + +- ✅ Copy [the `catalogApi.ts` file](./workspace/packages/app/src/catalogApi.ts) into your `packages/app/src` directory of the project where you develop your Backstage frontend. Then reference that file's API factory in your `packages/app/src/apis.ts` file, [as illustrated here](./workspace/packages/app/src/apis.ts). + +- ✅ Copy [the `catalogService.ts` file](./workspace/packages/backend/src/catalogService.ts) into your `packages/backend/src` directory of the project where you develop your Software Catalog backend. We will reference the file itself in the step below. + +After step 4 below is complete, these will be automatically picked up and used by all callers. + +> [!TIP] +> As a future refactor, you could instead break out these clients into a node and a react library that all your projects can import. That takes a few more steps and is left as a separate exercise. If you already have such libraries in your internal NPM, feel free to put them there to begin with and import from there. + +## 4. Split the catalog backend + +We'll now perform the actual split of the catalog backend. You will make separate config files that apply to each, and adapt the backend code to handle both cases seamlessly. + +- ✅ Duplicate your deployment. It's highly company dependent how this is done. Some may for example duplicate some declarative `Deployment` and `Service` k8s manifests etc, but it depends. + +- ✅ Copy [the `app-config.catalog-read.yaml`] and [the `app-config.catalog-write.yaml`] files into your project root. You must set up your read and write deployments to load their respective files with the `--config` flag, _in addition to_ the `app-config.yaml` file and possibly `app-config.production.yaml` that they already loaded. + +- ✅ Copy [the `config.d.ts`](./workspace/config.d.ts) file to your catalog backend directory at `packages/backend`. You should refer to it in the `package.json`'s `"files"` and `"configSchema"` fields [as per usual](https://backstage.io/docs/conf/defining). + +- ✅ Update your `packages/backend/src/index.ts` file to match [the proposed structure here](./workspace/packages/backend/src/index.ts). Note how it applies the custom catalog service we copied in the previous step, and has a separate section for write-only concerns. + +## 5. Region and database split + +After the above is deployed and working, you are well set up for some next step. + +- Scaling your readers across multiple regions and add geo-aware routing to them, while keeping writers in a "home" region +- Splitting the database server into a primary that the write nodes connect to, and regional secondaries with streaming replication from the primary + +But all of this is left as an exercise for the reader. + +## 6. Help make this smoother + +Congratulations on successfully performing your split! + +We would love [some help](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) with making this process easier for others. For example, if read nodes could automatically transparently proxy traffic to write nodes as needed, we would need far less fiddling with clients at a relatively small extra cost. diff --git a/contrib/catalog/read-write-split/workspace/app-config.catalog-read.yaml b/contrib/catalog/read-write-split/workspace/app-config.catalog-read.yaml new file mode 100644 index 0000000000..33d7f34714 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/app-config.catalog-read.yaml @@ -0,0 +1,12 @@ +# This file should be given to the catalog read nodes. + +backend: + database: + # disable running database migrations for every plugin/module + skipMigrations: true + +catalog: + role: read + + # disable processing engine + processingInterval: false diff --git a/contrib/catalog/read-write-split/workspace/app-config.catalog-write.yaml b/contrib/catalog/read-write-split/workspace/app-config.catalog-write.yaml new file mode 100644 index 0000000000..ea1659e140 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/app-config.catalog-write.yaml @@ -0,0 +1,4 @@ +# This file should be given to the catalog write nodes. + +catalog: + role: write diff --git a/contrib/catalog/read-write-split/workspace/app-config.yaml b/contrib/catalog/read-write-split/workspace/app-config.yaml new file mode 100644 index 0000000000..e4b09e4cb9 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/app-config.yaml @@ -0,0 +1,19 @@ +# This is in your regular app-config. + +# This introduces a made-up "catalog-write" plugin ID that the frontend catalog +# API implementation can use to resolve where to find the write nodes. +discovery: + endpoints: + # + # TODO: Replace with actual URLs + # + # NOTE: Each target can also be an object with "internal" and "external" + # keys with different URLs, if they should be different when called by + # backends and the frontend, respectively. + # + - target: https://catalog-read.example.net/api/catalog + plugins: + - catalog + - target: https://catalog-write.example.net/api/catalog + plugins: + - catalog-write diff --git a/contrib/catalog/read-write-split/workspace/config.d.ts b/contrib/catalog/read-write-split/workspace/config.d.ts new file mode 100644 index 0000000000..29a80c77f8 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/config.d.ts @@ -0,0 +1,5 @@ +export interface Config { + catalog: { + role: 'read' | 'write'; + }; +} diff --git a/contrib/catalog/read-write-split/workspace/packages/app/src/apis.ts b/contrib/catalog/read-write-split/workspace/packages/app/src/apis.ts new file mode 100644 index 0000000000..12fd2bfd49 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/packages/app/src/apis.ts @@ -0,0 +1,11 @@ +import { AnyApiFactory } from '@backstage/core-plugin-api'; +import { catalogApiFactory } from './catalogApi'; + +// This file is already present in a typical Backstage app. We are just adding +// the catalog API factory here to ensure that the frontend sends requests to +// the correct set of catalog nodes depending on whether it's a read or a write +// operation. +export const apis: AnyApiFactory[] = [ + // ...other APIs here... + catalogApiFactory, +]; diff --git a/contrib/catalog/read-write-split/workspace/packages/app/src/catalogApi.ts b/contrib/catalog/read-write-split/workspace/packages/app/src/catalogApi.ts new file mode 100644 index 0000000000..0813249f8f --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/packages/app/src/catalogApi.ts @@ -0,0 +1,174 @@ +import { + AddLocationRequest, + AddLocationResponse, + CatalogApi, + CatalogClient, + CatalogRequestOptions, + GetEntitiesByRefsRequest, + GetEntitiesByRefsResponse, + GetEntitiesRequest, + GetEntitiesResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, + GetEntityFacetsRequest, + GetEntityFacetsResponse, + GetLocationsResponse, + Location, + QueryEntitiesRequest, + QueryEntitiesResponse, + ValidateEntityResponse, +} from '@backstage/catalog-client'; +import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { + createApiFactory, + DiscoveryApi, + discoveryApiRef, + FetchApi, + fetchApiRef, +} from '@backstage/core-plugin-api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; + +/** + * Implements the catalog client for frontends, by using a custom service + * discovery to achieve read/write segregation. + */ +export class ReadWriteSplitCatalogClient implements CatalogApi { + #write: CatalogApi; + #read: CatalogApi; + + constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) { + this.#read = new CatalogClient({ + fetchApi: options.fetchApi, + discoveryApi: { + // This uses the normal "catalog" plugin ID + getBaseUrl: () => options.discoveryApi.getBaseUrl('catalog'), + }, + }); + this.#write = new CatalogClient({ + fetchApi: options.fetchApi, + discoveryApi: { + // This uses the made-up "catalog-write" plugin ID (see app-config.yaml + // which defines a custom discovery endpoint for this) + getBaseUrl: () => options.discoveryApi.getBaseUrl('catalog-write'), + }, + }); + } + + getEntities( + request?: GetEntitiesRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getEntities(request, options); + } + + getEntitiesByRefs( + request: GetEntitiesByRefsRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getEntitiesByRefs(request, options); + } + + queryEntities( + request?: QueryEntitiesRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.queryEntities(request, options); + } + + getEntityAncestors( + request: GetEntityAncestorsRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getEntityAncestors(request, options); + } + + getEntityByRef( + entityRef: string | CompoundEntityRef, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getEntityByRef(entityRef, options); + } + + removeEntityByUid( + uid: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#write.removeEntityByUid(uid, options); + } + + refreshEntity( + entityRef: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#write.refreshEntity(entityRef, options); + } + + getEntityFacets( + request: GetEntityFacetsRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getEntityFacets(request, options); + } + + getLocations( + request?: {}, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getLocations(request, options); + } + + getLocationById( + id: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getLocationById(id, options); + } + + getLocationByRef( + locationRef: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getLocationByRef(locationRef, options); + } + + addLocation( + location: AddLocationRequest, + options?: CatalogRequestOptions, + ): Promise { + return this.#write.addLocation(location, options); + } + + removeLocationById( + id: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#write.removeLocationById(id, options); + } + + getLocationByEntity( + entityRef: string | CompoundEntityRef, + options?: CatalogRequestOptions, + ): Promise { + return this.#read.getLocationByEntity(entityRef, options); + } + + validateEntity( + entity: Entity, + locationRef: string, + options?: CatalogRequestOptions, + ): Promise { + return this.#write.validateEntity(entity, locationRef, options); + } +} + +// You should pass this to createApp. +export const catalogApiFactory = createApiFactory({ + api: catalogApiRef, + deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, + factory: ({ discoveryApi, fetchApi }) => { + return new ReadWriteSplitCatalogClient({ + discoveryApi, + fetchApi, + }); + }, +}); diff --git a/contrib/catalog/read-write-split/workspace/packages/backend/src/catalogService.ts b/contrib/catalog/read-write-split/workspace/packages/backend/src/catalogService.ts new file mode 100644 index 0000000000..80711bd4b3 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/packages/backend/src/catalogService.ts @@ -0,0 +1,231 @@ +import { + AuthService, + coreServices, + createServiceFactory, + DiscoveryService, +} from '@backstage/backend-plugin-api'; +import { + AddLocationRequest, + AddLocationResponse, + CatalogApi, + CatalogClient, + CatalogRequestOptions, + GetEntitiesByRefsRequest, + GetEntitiesByRefsResponse, + GetEntitiesRequest, + GetEntitiesResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, + GetEntityFacetsRequest, + GetEntityFacetsResponse, + GetLocationsResponse, + Location, + QueryEntitiesRequest, + QueryEntitiesResponse, + ValidateEntityResponse, +} from '@backstage/catalog-client'; +import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { + CatalogService, + CatalogServiceRequestOptions, + catalogServiceRef, +} from '@backstage/plugin-catalog-node'; + +/** + * Implements the catalog client for backends, by using a custom service + * discovery to achieve read/write segregation. + */ +export class ReadWriteSplitCatalogService implements CatalogService { + readonly #auth: AuthService; + readonly #catalogRead: CatalogApi; + readonly #catalogWrite: CatalogApi; + + constructor(options: { auth: AuthService; discovery: DiscoveryService }) { + this.#auth = options.auth; + this.#catalogRead = new CatalogClient({ + discoveryApi: { + // This uses the normal "catalog" plugin ID + getBaseUrl: () => options.discovery.getBaseUrl('catalog'), + }, + }); + this.#catalogWrite = new CatalogClient({ + discoveryApi: { + // This uses the made-up "catalog-write" plugin ID (see app-config.yaml + // which defines a custom discovery endpoint for this) + getBaseUrl: () => options.discovery.getBaseUrl('catalog-write'), + }, + }); + } + + async getEntities( + request: GetEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getEntities( + request, + await this.#getOptions(options), + ); + } + + async getEntitiesByRefs( + request: GetEntitiesByRefsRequest, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getEntitiesByRefs( + request, + await this.#getOptions(options), + ); + } + + async queryEntities( + request: QueryEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.queryEntities( + request, + await this.#getOptions(options), + ); + } + + async getEntityAncestors( + request: GetEntityAncestorsRequest, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getEntityAncestors( + request, + await this.#getOptions(options), + ); + } + + async getEntityByRef( + entityRef: string | CompoundEntityRef, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getEntityByRef( + entityRef, + await this.#getOptions(options), + ); + } + + async removeEntityByUid( + uid: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogWrite.removeEntityByUid( + uid, + await this.#getOptions(options), + ); + } + + async refreshEntity( + entityRef: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogWrite.refreshEntity( + entityRef, + await this.#getOptions(options), + ); + } + + async getEntityFacets( + request: GetEntityFacetsRequest, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getEntityFacets( + request, + await this.#getOptions(options), + ); + } + + async getLocations( + options: CatalogRequestOptions, + ): Promise { + return this.#catalogRead.getLocations(options); + } + + async getLocationById( + id: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getLocationById( + id, + await this.#getOptions(options), + ); + } + + async getLocationByRef( + locationRef: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getLocationByRef( + locationRef, + await this.#getOptions(options), + ); + } + + async addLocation( + location: AddLocationRequest, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogWrite.addLocation( + location, + await this.#getOptions(options), + ); + } + + async removeLocationById( + id: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogWrite.removeLocationById( + id, + await this.#getOptions(options), + ); + } + + async getLocationByEntity( + entityRef: string | CompoundEntityRef, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogRead.getLocationByEntity( + entityRef, + await this.#getOptions(options), + ); + } + + async validateEntity( + entity: Entity, + locationRef: string, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogWrite.validateEntity( + entity, + locationRef, + await this.#getOptions(options), + ); + } + + async #getOptions( + options: CatalogServiceRequestOptions, + ): Promise { + return this.#auth.getPluginRequestToken({ + onBehalfOf: options.credentials, + targetPluginId: 'catalog', + }); + } +} + +// You should register this in your backend. +export const catalogService = createServiceFactory({ + service: catalogServiceRef, + deps: { + auth: coreServices.auth, + discovery: coreServices.discovery, + }, + async factory({ auth, discovery }) { + return new ReadWriteSplitCatalogService({ + auth, + discovery, + }); + }, +}); diff --git a/contrib/catalog/read-write-split/workspace/packages/backend/src/index.ts b/contrib/catalog/read-write-split/workspace/packages/backend/src/index.ts new file mode 100644 index 0000000000..0d8e9e41d9 --- /dev/null +++ b/contrib/catalog/read-write-split/workspace/packages/backend/src/index.ts @@ -0,0 +1,34 @@ +import { createBackend } from '@backstage/backend-defaults'; +import { + coreServices, + createBackendFeatureLoader, +} from '@backstage/backend-plugin-api'; +import { catalogService } from './catalogService'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(catalogService); +// Here at the root level, you can add more features that you want to apply to +// BOTH the read and write nodes, as needed. + +backend.add( + createBackendFeatureLoader({ + deps: { config: coreServices.rootConfig }, + async *loader({ config }) { + if (config.getString('catalog.role') !== 'write') { + return; + } + + // Here inside the loader, you can add more features that you want to + // apply to ONLY the write nodes, as needed. This is where providers and + // processors go, for example. The incremental ingestion provider line + // below is just an example. + yield import( + '@backstage/plugin-catalog-backend-module-incremental-ingestion' + ); + }, + }), +); + +backend.start(); diff --git a/canon-docs/.eslintrc.json b/docs-ui/.eslintrc.json similarity index 100% rename from canon-docs/.eslintrc.json rename to docs-ui/.eslintrc.json diff --git a/canon-docs/.gitignore b/docs-ui/.gitignore similarity index 100% rename from canon-docs/.gitignore rename to docs-ui/.gitignore diff --git a/canon-docs/README.md b/docs-ui/README.md similarity index 60% rename from canon-docs/README.md rename to docs-ui/README.md index d91076c4cd..41b9921413 100644 --- a/canon-docs/README.md +++ b/docs-ui/README.md @@ -1,6 +1,6 @@ -# Canon Docs +# Backstage UI Docs -Canon is our internal UI library built for Backstage. We built this website to document the library and its components. You can view this website [here](https://canon.backstage.io). +Backstage UI is our internal UI library built for Backstage. We built this website to document the library and its components. You can view this website [here](https://ui.backstage.io). ## How to run locally diff --git a/canon-docs/next.config.mjs b/docs-ui/next.config.mjs similarity index 100% rename from canon-docs/next.config.mjs rename to docs-ui/next.config.mjs diff --git a/canon-docs/package.json b/docs-ui/package.json similarity index 68% rename from canon-docs/package.json rename to docs-ui/package.json index dba4abb78f..6fd29e0678 100644 --- a/canon-docs/package.json +++ b/docs-ui/package.json @@ -1,12 +1,15 @@ { - "name": "canon-docs", + "name": "docs-ui", "version": "0.1.0", "private": true, "scripts": { - "build": "npm run build:css && next build", - "build:css": "node scripts/build-css.js", + "prebuild": "yarn sync:css", + "build": "next build", "lint": "next lint", - "start": "npm run build:css && next dev" + "prestart": "yarn sync:css", + "start": "concurrently \"yarn sync:css:watch\" \"next dev\"", + "sync:css": "node scripts/sync-css.js", + "sync:css:watch": "node scripts/sync-css.js --watch" }, "resolutions": { "@types/react": "19.1.8", @@ -14,10 +17,12 @@ }, "dependencies": { "@codemirror/lang-sass": "^6.0.2", + "@codemirror/view": "^6.34.4", "@lezer/highlight": "^1.2.1", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "15.3.4", + "@remixicon/react": "^4.6.0", "@storybook/react": "^8.6.8", "@uiw/codemirror-themes": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", @@ -25,9 +30,9 @@ "motion": "^12.4.1", "next": "15.3.4", "next-mdx-remote-client": "^2.1.2", + "prop-types": "^15.8.1", "react": "19.1.0", "react-dom": "19.1.0", - "react-frame-component": "^5.2.7", "shiki": "^1.26.1", "storybook": "^8.6.8" }, @@ -36,6 +41,8 @@ "@types/node": "^20", "@types/react": "19.1.8", "@types/react-dom": "19.1.6", + "chokidar": "^3.6.0", + "concurrently": "^8.2.2", "eslint": "^8", "eslint-config-next": "15.3.4", "lightningcss": "^1.28.2", diff --git a/canon-docs/public/.nojekyll b/docs-ui/public/.nojekyll similarity index 100% rename from canon-docs/public/.nojekyll rename to docs-ui/public/.nojekyll diff --git a/docs-ui/public/CNAME b/docs-ui/public/CNAME new file mode 100644 index 0000000000..21060e506a --- /dev/null +++ b/docs-ui/public/CNAME @@ -0,0 +1 @@ +ui.backstage.io diff --git a/canon-docs/public/css-classname-structure.png b/docs-ui/public/css-classname-structure.png similarity index 100% rename from canon-docs/public/css-classname-structure.png rename to docs-ui/public/css-classname-structure.png diff --git a/docs-ui/public/theme-backstage.css b/docs-ui/public/theme-backstage.css new file mode 100644 index 0000000000..1d70d33f73 --- /dev/null +++ b/docs-ui/public/theme-backstage.css @@ -0,0 +1,2 @@ +/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ +@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}}.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(--pl-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(--pl-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(--pl-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(--pl-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(--pl-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(--pr-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(--pr-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(--pr-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(--pr-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(--pr-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(--pt-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(--pt-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(--pt-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(--pt-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(--pt-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(--pb-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(--pb-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(--pb-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(--pb-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(--pb-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(--py-xs);margin-bottom:var(--py-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(--py-sm);margin-bottom:var(--py-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(--py-md);margin-bottom:var(--py-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(--py-lg);margin-bottom:var(--py-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(--py-xl);margin-bottom:var(--py-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(--px-xs);margin-right:var(--px-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(--px-sm);margin-right:var(--px-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(--px-md);margin-right:var(--px-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(--px-lg);margin-right:var(--px-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(--px-xl);margin-right:var(--px-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-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}}:where(a){color:inherit;text-decoration:none}@keyframes pulse{50%{opacity:.5}}: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=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}.bui-AvatarRoot{vertical-align:middle;user-select:none;color:var(--bui-fg-primary);background-color:var(--bui-bg-surface-2);border-radius:100%;justify-content:center;align-items:center;width:2rem;height:2rem;font-size:1rem;font-weight:500;line-height:1;display:inline-flex;overflow:hidden}.bui-AvatarRoot[data-size=small]{width:1.5rem;height:1.5rem}.bui-AvatarRoot[data-size=medium]{width:2rem;height:2rem}.bui-AvatarRoot[data-size=large]{width:3rem;height:3rem}.bui-AvatarImage{object-fit:cover;width:100%;height:100%}.bui-AvatarFallback{width:100%;height:100%;font-size:var(--bui-font-size-3);font-weight:var(--bui-font-weight-regular);box-shadow:inset 0 0 0 1px var(--bui-border);border-radius:var(--bui-radius-full);justify-content:center;align-items:center;display:flex}.bui-Box{font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);color:var(--bui-fg-primary)}.bui-Button{user-select:none;font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-bold);cursor:pointer;border-radius:var(--bui-radius-2);justify-content:center;align-items:center;gap:var(--bui-space-1_5);border:none;flex-shrink:0;padding:0;display:inline-flex;&[data-disabled=true]{cursor:not-allowed}}.bui-Button[data-variant=primary]{background-color:var(--bui-bg-solid);color:var(--bui-fg-solid);&:hover{background-color:var(--bui-bg-solid-hover);transition:background-color .15s}&:active{background-color:var(--bui-bg-solid-pressed)}&:focus-visible{outline:2px solid var(--bui-ring);outline-offset:2px}&[data-disabled=true]{background-color:var(--bui-bg-solid-disabled);color:var(--bui-fg-solid-disabled)}}.bui-Button[data-variant=secondary]{background-color:var(--bui-bg-surface-1);box-shadow:inset 0 0 0 1px var(--bui-border);color:var(--bui-fg-primary);&:hover{box-shadow:inset 0 0 0 1px var(--bui-border-hover);transition:box-shadow .15s}&:active{box-shadow:inset 0 0 0 1px var(--bui-border-pressed)}&:focus-visible{box-shadow:inset 0 0 0 2px var(--bui-ring);outline:none;transition:none}&[data-disabled=true]{box-shadow:inset 0 0 0 1px var(--bui-border-disabled);color:var(--bui-fg-disabled)}}.bui-Button[data-variant=tertiary]{color:var(--bui-fg-primary);background-color:#0000;&:hover{background-color:var(--bui-bg-surface-1);transition:background-color .2s}&:active{background-color:var(--bui-bg-surface-2)}&:focus-visible{box-shadow:inset 0 0 0 2px var(--bui-ring);outline:none;transition:none}&[data-disabled=true]{color:var(--bui-fg-disabled);background-color:#0000}}.bui-Button[data-size=medium]{font-size:var(--bui-font-size-4);padding:0 var(--bui-space-3);height:2.5rem}.bui-Button[data-size=small]{font-size:var(--bui-font-size-3);padding:0 var(--bui-space-2);height:2rem}.bui-Button[data-size=small] svg{width:1rem;height:1rem}.bui-Button[data-size=medium] svg{width:1.25rem;height:1.25rem}.bui-ButtonIcon{justify-content:center;align-items:center}.bui-ButtonIcon[data-size=small]{width:2rem;padding:0}.bui-ButtonIcon[data-size=medium]{width:2.5rem;padding:0}.bui-Card{gap:var(--bui-space-3);background-color:var(--bui-bg-surface-1);border-radius:var(--bui-radius-3);padding-block:var(--bui-space-3);color:var(--bui-fg-primary);border:1px solid var(--bui-border);flex-direction:column;width:100%;min-height:0;display:flex;overflow:hidden}.bui-CardBody{flex:1;min-height:0;overflow:auto}.bui-CardHeader,.bui-CardFooter{padding-inline:var(--bui-space-3)}.bui-CheckboxRoot{width:1rem;height:1rem;box-shadow:inset 0 0 0 1px var(--bui-border);cursor:pointer;background-color:var(--bui-bg-surface-1);border:none;border-radius:2px;flex-shrink:0;justify-content:center;align-items:center;padding:0;transition:background-color .2s ease-in-out;display:flex}.bui-CheckboxRoot:focus-visible{outline:2px solid var(--bui-ring);outline-offset:2px;transition:none}.bui-CheckboxRoot[data-checked]{background-color:var(--bui-bg-solid);box-shadow:none;color:var(--bui-fg-solid)}.bui-CheckboxLabel{align-items:center;gap:var(--bui-space-2);font-size:var(--bui-font-size-3);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);color:var(--bui-fg-primary);user-select:none;flex-direction:row;display:flex;&:hover{& .bui-CheckboxRoot:not([data-checked]){box-shadow:inset 0 0 0 1px var(--bui-border-hover)}}}.bui-CheckboxIndicator{color:var(--bui-fg-solid);justify-content:center;align-items:center;display:flex}.bui-CollapsiblePanel{height:var(--collapsible-panel-height);transition:all .15s ease-out;display:flex;overflow:hidden;&[data-starting-style],&[data-ending-style]{height:0}}.bui-Container{max-width:120rem;padding-inline:var(--bui-space-4);margin-inline:auto;transition:padding .2s ease-in-out}@media (width>=640px){.bui-Container{padding-inline:var(--bui-space-5)}}.bui-DataTableRoot{gap:var(--bui-space-3);flex-direction:column;display:flex}.bui-DataTablePagination{padding-top:var(--bui-space-5);justify-content:space-between;align-items:center;display:flex}.bui-DataTablePagination--left{justify-content:space-between;align-items:center;display:flex}.bui-DataTablePagination--right{justify-content:space-between;align-items:center;gap:var(--bui-space-2);display:flex}.bui-DataTablePagination--select{min-width:10.5rem}.bui-FieldError{color:var(--bui-fg-danger);font-size:var(--bui-font-size-2);font-weight:var(--bui-font-weight-regular);margin-top:var(--bui-space-2);display:inline-block}.bui-FieldLabelWrapper{margin-bottom:var(--bui-space-3);gap:var(--bui-space-1);flex-direction:column;display:flex}.bui-FieldLabel{color:var(--bui-fg-primary);cursor:pointer;font-weight:var(--bui-font-weight-regular);font-size:var(--bui-font-size-2);margin-right:auto}.bui-FieldSecondaryLabel{color:var(--bui-fg-secondary);font-weight:var(--bui-font-weight-regular);margin-left:var(--bui-space-1)}.bui-FieldDescription{font-weight:var(--bui-font-weight-regular);font-size:var(--bui-font-size-2);color:var(--bui-fg-secondary);margin:0}.bui-Flex{min-width:0;display:flex}.bui-Grid{display:grid}.bui-HeaderToolbar{z-index:10;margin-bottom:var(--bui-space-6);position:sticky;top:0;&:before{content:"";background-color:var(--bui-bg);z-index:0;height:16px;position:absolute;top:0;left:0;right:0}&[data-has-tabs=true]{margin-bottom:0}}.bui-HeaderToolbarWrapper{z-index:1;background-color:var(--bui-bg-surface-1);padding-inline:var(--bui-space-5);border-bottom:1px solid var(--bui-border);color:var(--bui-fg-primary);flex-direction:row;justify-content:space-between;align-items:center;height:52px;display:flex;position:relative}.bui-HeaderToolbarContent{align-items:center;gap:var(--bui-space-2);flex-direction:row;display:flex}.bui-HeaderToolbarName{align-items:center;gap:var(--bui-space-2);font-size:var(--bui-font-size-3);font-weight:var(--bui-font-weight-regular);flex-direction:row;flex-shrink:0;display:flex}.bui-HeaderToolbarIcon{width:16px;height:16px;color:var(--bui-fg-primary);& svg{width:100%;height:100%}}.bui-HeaderToolbarControls{right:var(--bui-space-5);align-items:center;gap:var(--bui-space-2);flex-direction:row;display:flex;position:absolute;top:50%;transform:translateY(-50%)}.bui-HeaderBreadcrumbs{align-items:center;gap:var(--bui-space-2);font-size:var(--bui-font-size-3);font-weight:var(--bui-font-weight-regular);flex-direction:row;display:flex}.bui-HeaderBreadcrumb{align-items:center;gap:var(--bui-space-2);flex-direction:row;display:flex}.bui-HeaderBreadcrumbLink{color:var(--bui-fg-secondary);cursor:pointer;text-decoration:none;&[data-active=true]{color:var(--bui-fg-primary)}}.bui-HeaderBreadcrumbSeparator{width:16px;height:16px;color:var(--bui-fg-secondary)}.bui-HeaderTabsWrapper{margin-bottom:var(--bui-space-4);padding-inline:var(--bui-space-3);border-bottom:1px solid var(--bui-border);background-color:var(--bui-bg-surface-1)}.bui-HeaderPage{gap:var(--bui-space-1);padding-inline:var(--bui-space-5);margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6);flex-direction:column;display:flex}.bui-HeaderPageContent{flex-direction:row;justify-content:space-between;display:flex}.bui-HeaderPageTabsWrapper{margin-left:-8px}.bui-HeaderPageControls{align-items:center;gap:var(--bui-space-2);flex-direction:row;display:flex}.bui-Icon{width:1rem;height:1rem}.bui-Link{font-family:var(--bui-font-regular);cursor:pointer;margin:0;padding:0;text-decoration-line:none;display:inline-block;&:hover{text-underline-offset:calc(.025em + 2px);text-decoration-line:underline;text-decoration-style:solid;text-decoration-thickness:min(2px,max(1px,.05em));text-decoration-color:color-mix(in srgb,currentColor 30%,transparent)}}.bui-MenuPositioner{z-index:100;outline:0}.bui-MenuPopup{background-color:var(--bui-bg-surface-1);border:1px solid var(--bui-border);color:var(--bui-fg-primary);transform-origin:var(--transform-origin);max-width:min(var(--available-width),340px);max-height:min(var(--available-height),500px);padding-bottom:var(--bui-space-1);border-radius:.375rem;outline:none;flex-direction:column;transition:transform .15s,opacity .15s;display:flex;position:relative;overflow:auto;&[data-starting-style],&[data-ending-style]{opacity:0;transform:scale(.9)}}.bui-MenuItem{user-select:none;align-items:center;gap:var(--bui-space-2);height:32px;color:var(--bui-fg-primary);border-radius:var(--bui-radius-2);margin-inline:var(--bui-space-1);padding-inline:var(--bui-space-2);font-size:var(--bui-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;&:first-child{margin-top:var(--bui-space-1)}&[data-highlighted]{background-color:var(--bui-gray-3)}}.bui-MenuSubmenuTrigger{user-select:none;justify-content:space-between;align-items:center;gap:var(--bui-space-2);height:32px;color:var(--bui-fg-primary);border-radius:var(--bui-radius-2);margin-inline:var(--bui-space-1);padding-inline:var(--bui-space-2);font-size:var(--bui-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;& .bui-Icon{color:var(--bui-fg-secondary)}&:first-child{margin-top:var(--bui-space-1)}&[data-popup-open],&[data-highlighted]{background-color:var(--bui-gray-3);& .bui-Icon{color:var(--bui-fg-primary)}}}.bui-MenuSeparator{background-color:var(--color-gray-200);height:1px;margin:.375rem 1rem}.bui-SubmenuComboboxSearch{padding-inline:var(--bui-space-3);border:none;border-bottom:1px solid var(--bui-border);background-color:var(--bui-bg-surface-1);width:100%;height:32px;color:var(--bui-fg-primary);line-height:140%;font-size:var(--bui-font-size-3);z-index:1;outline:none;position:sticky;top:0;&::placeholder{color:var(--bui-fg-secondary)}&:disabled{opacity:.6;cursor:not-allowed}}.bui-SubmenuComboboxItems{padding-top:var(--bui-space-2);outline:none;flex-direction:column;display:flex;overflow-y:auto}.bui-SubmenuComboboxNoResults{padding-inline:var(--bui-space-3);padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-4);color:var(--bui-fg-secondary);font-size:var(--bui-font-size-3)}.bui-SubmenuComboboxItem{user-select:none;justify-content:space-between;align-items:center;gap:var(--bui-space-2);height:32px;color:var(--bui-fg-primary);border-radius:var(--bui-radius-2);margin-inline:var(--bui-space-1);padding-inline:var(--bui-space-2);font-size:var(--bui-font-size-3);cursor:pointer;outline:0;flex-shrink:0;text-decoration:none;display:flex;&[data-highlighted]{background-color:var(--bui-gray-3)}&[data-disabled]{opacity:.5;cursor:not-allowed}}.bui-SubmenuComboboxItemCheckbox{width:16px;height:16px;color:var(--bui-fg-primary);border-radius:var(--bui-radius-2);border:1px solid var(--bui-border);background:var(--bui-bg-surface-1);flex-shrink:0;justify-content:center;align-items:center;display:flex}.bui-SubmenuComboboxItemLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.bui-Popover{background-color:var(--bui-bg-surface-1);border:1px solid var(--bui-border);border-radius:var(--bui-radius-3);padding-block:var(--bui-space-1);margin-right:12px;overflow:scroll;box-shadow:0 4px 12px #0000001a}.bui-RadioGroup{color:var(--bui-fg-primary);flex-direction:column;display:flex}.bui-RadioGroup[data-orientation=horizontal] .bui-RadioGroupContent{gap:var(--bui-space-4);flex-direction:row}.bui-RadioGroupContent{gap:var(--bui-space-2);flex-direction:column;display:flex}.bui-Radio{align-items:center;gap:var(--bui-space-2);font-size:var(--bui-font-size-2);color:var(--bui-fg-primary);forced-color-adjust:none;display:flex;position:relative;&:before{content:"";box-sizing:border-box;border:.125rem solid var(--bui-border);background:var(--bui-gray-1);border-radius:var(--bui-radius-full);width:1rem;height:1rem;transition:all .2s;display:block}&[data-pressed]:before{border-color:var(--bui-border)}&[data-selected]{&:before{border-color:var(--bui-bg-solid);border-width:.25rem}&[data-pressed]:before{border-color:var(--bui-bg-solid)}}&[data-focus-visible]:before{outline:2px solid var(--bui-ring);outline-offset:2px}&[data-disabled]{cursor:not-allowed;color:var(--bui-fg-disabled);&:before{border-color:var(--bui-border-disabled);background:var(--bui-bg-disabled)}&[data-selected]:before{border-color:var(--bui-border-disabled)}}&[data-invalid]:before,&[data-invalid][data-selected]:before{border-color:var(--bui-border-danger)}&[data-disabled][data-invalid]{color:var(--bui-fg-disabled);&:before{border-color:var(--bui-border-disabled);background:var(--bui-bg-disabled)}&[data-selected]:before{border-color:var(--bui-border-disabled)}}}.bui-TableRoot{caption-side:bottom;border-collapse:collapse;width:100%}.bui-TableHead{text-align:left;padding:var(--bui-space-3);font-size:var(--bui-font-size-3);color:var(--bui-fg-primary)}.bui-TableBody{color:var(--bui-fg-primary)}.bui-TableRow{border-bottom:1px solid var(--bui-border);transition:color .2s ease-in-out}.bui-TableBody .bui-TableRow:hover{background-color:var(--bui-gray-2)}.bui-TableCell{padding:var(--bui-space-3);font-size:var(--bui-font-size-3)}.bui-TableCellText,.bui-TableCellLink{gap:var(--bui-space-0_5);flex-direction:column;display:flex}.bui-TableCellProfile{gap:var(--bui-space-2);flex-direction:row;align-items:center;display:flex}.bui-TableCellProfileAvatar{vertical-align:middle;user-select:none;color:var(--bui-fg-primary);background-color:var(--bui-bg-surface-2);border-radius:100%;justify-content:center;align-items:center;width:1.25rem;height:1.25rem;font-size:1rem;font-weight:500;line-height:1;display:inline-flex;overflow:hidden}.bui-TableCellProfileAvatarImage{object-fit:cover;width:100%;height:100%}.bui-TableCellProfileAvatarFallback{width:100%;height:100%;font-size:var(--bui-font-size-2);font-weight:var(--bui-font-weight-regular);box-shadow:inset 0 0 0 1px var(--bui-border);border-radius:var(--bui-radius-full);justify-content:center;align-items:center;display:flex}.bui-Tabs{--active-tab-left:0px;--active-tab-right:0px;--active-tab-top:0px;--active-tab-bottom:0px;--active-tab-width:0px;--active-tab-height:0px;--active-transition-duration:0s;--hovered-tab-left:0px;--hovered-tab-right:0px;--hovered-tab-top:0px;--hovered-tab-bottom:0px;--hovered-tab-width:0px;--hovered-tab-height:0px;--hovered-tab-opacity:0;--hovered-transition-duration:0s}.bui-TabList{flex-direction:row;display:flex}.bui-TabListWrapper{position:relative}.bui-Tab{font-size:var(--bui-font-size-3);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);color:var(--bui-fg-secondary);cursor:pointer;z-index:2;height:36px;padding-inline:var(--bui-space-2);justify-content:center;align-items:center;display:flex;position:relative;&[data-selected=true]{color:var(--bui-fg-primary)}}.bui-TabActive{content:"";left:calc(var(--active-tab-left) + var(--bui-space-2));width:calc(var(--active-tab-width) - var(--bui-space-4));background-color:var(--bui-fg-primary);height:1px;transition:left var(--active-transition-duration)ease-out,opacity .15s ease-out,width var(--active-transition-duration)ease-out;opacity:1;border-radius:4px;position:absolute;bottom:-1px}.bui-TabHovered{content:"";left:var(--hovered-tab-left);top:calc(var(--hovered-tab-top) + 4px);width:var(--hovered-tab-width);height:calc(var(--hovered-tab-height) - 8px);background-color:var(--bui-gray-2);opacity:var(--hovered-tab-opacity);transition:left var(--hovered-transition-duration)ease-out,top var(--hovered-transition-duration)ease-out,width var(--hovered-transition-duration)ease-out,height var(--hovered-transition-duration)ease-out,opacity .15s ease-out;border-radius:4px;position:absolute}.bui-TabPanel{padding-inline:var(--bui-space-2);padding-top:var(--bui-space-4)}.bui-Text{font-family:var(--bui-font-regular);margin:0;padding:0}.bui-Text[data-variant=title-large]{font-size:var(--bui-font-size-8);line-height:140%}.bui-Text[data-variant=title-medium]{font-size:var(--bui-font-size-7);line-height:140%}.bui-Text[data-variant=title-small]{font-size:var(--bui-font-size-6);line-height:140%}.bui-Text[data-variant=title-x-small]{font-size:var(--bui-font-size-5);line-height:140%}.bui-Text[data-variant=body-large]{font-size:var(--bui-font-size-4);line-height:140%}.bui-Text[data-variant=body-medium]{font-size:var(--bui-font-size-3);line-height:140%}.bui-Text[data-variant=body-small]{font-size:var(--bui-font-size-2);line-height:140%}.bui-Text[data-variant=body-x-small]{font-size:var(--bui-font-size-1);line-height:140%}.bui-Text[data-weight=regular]{font-weight:var(--bui-font-weight-regular)}.bui-Text[data-weight=bold]{font-weight:var(--bui-font-weight-bold)}.bui-Text[data-color=primary]{color:var(--bui-fg-primary)}.bui-Text[data-color=secondary]{color:var(--bui-fg-secondary)}.bui-Text[data-color=danger]{color:var(--bui-fg-danger)}.bui-Text[data-color=warning]{color:var(--bui-fg-warning)}.bui-Text[data-color=success]{color:var(--bui-fg-success)}.bui-Text[data-truncate]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.bui-Text[data-as=span],.bui-Text[data-as=label],.bui-Text[data-as=strong],.bui-Text[data-as=em],.bui-Text[data-as=small]{display:inline-block}.bui-TextField{font-family:var(--bui-font-regular);flex-direction:column;width:100%;display:flex}.bui-InputWrapper{position:relative;&[data-size=small] .bui-Input{height:2rem}&[data-size=medium] .bui-Input{height:2.5rem}&[data-size=small] .bui-Input[data-icon]{padding-left:var(--bui-space-8)}&[data-size=medium] .bui-Input[data-icon]{padding-left:var(--bui-space-9)}}.bui-InputIcon{left:var(--bui-space-3);margin-right:var(--bui-space-1);color:var(--bui-fg-primary);flex-shrink:0;position:absolute;top:50%;transform:translateY(-50%);&[data-size=small],&[data-size=small] svg{width:1rem;height:1rem}&[data-size=medium],&[data-size=medium] svg{width:1.25rem;height:1.25rem}}.bui-Input{padding:0 var(--bui-space-3);border-radius:var(--bui-radius-3);border:1px solid var(--bui-border);background-color:var(--bui-bg-surface-1);font-size:var(--bui-font-size-3);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);color:var(--bui-fg-primary);width:100%;height:100%;cursor:inherit;align-items:center;transition:border-color .2s ease-in-out,outline-color .2s ease-in-out;display:flex;&::-webkit-search-cancel-button,&::-webkit-search-decoration{-webkit-appearance:none}&::placeholder{color:var(--bui-fg-secondary)}&[data-focused]{outline-color:var(--bui-border-pressed);outline-width:0}&[data-hovered]{border-color:var(--bui-border-hover)}&[data-focused]{border-color:var(--bui-border-pressed);outline-width:0}&[data-invalid]{border-color:var(--bui-fg-danger)}&[data-disabled]{opacity:.5;cursor:not-allowed;border:1px solid var(--bui-border-disabled)}}.bui-SearchField[data-empty] .bui-InputClear{display:none}.bui-InputClear{cursor:pointer;color:var(--bui-fg-secondary);background-color:#0000;border:none;justify-content:center;align-items:center;margin:0;padding:0;transition:color .2s ease-in-out;display:flex;position:absolute;top:0;bottom:0;right:0}.bui-InputClear:hover{color:var(--bui-fg-primary)}.bui-InputClear[data-size=small]{width:2rem;height:2rem}.bui-InputClear[data-size=medium]{width:2.5rem;height:2.5rem}.bui-InputClear svg{width:1rem;height:1rem}.bui-Skeleton{animation:var(--bui-animate-pulse);background-color:var(--bui-bg-surface-2);border-radius:var(--bui-radius-2)}.bui-Skeleton[data-rounded=true]{border-radius:var(--bui-radius-full)}.bui-Tooltip{background:var(--bui-bg-surface-1);border:1px solid var(--bui-gray-3);forced-color-adjust:none;padding:var(--bui-space-2)var(--bui-space-3);max-width:240px;font-size:var(--bui-font-size-3);font-family:var(--bui-font-regular);color:var(--bui-fg-primary);--tooltip-offset:var(--bui-space-3);border-radius:4px;outline:none;transition:transform .2s,opacity .2s;transform:translate(0,0);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;&[data-entering],&[data-exiting]{transform:var(--origin);opacity:0}&[data-placement=top]{margin-bottom:var(--tooltip-offset);--origin:translateY(4px)}&[data-placement=right]{margin-left:var(--tooltip-offset);--origin:translateX(-4px)}&[data-placement=bottom]{margin-top:var(--tooltip-offset);--origin:translateY(-4px)}&[data-placement=left]{margin-right:var(--tooltip-offset);--origin:translateX(4px)}}.bui-TooltipArrow{& svg{--tooltip-arrow-overlap:-2px;display:block;& path:first-child{fill:var(--bui-bg-surface-1)}& path:nth-child(2){fill:var(--bui-gray-3)}}&[data-placement=top] svg{margin-top:var(--tooltip-arrow-overlap)}&[data-placement=bottom] svg{margin-bottom:var(--tooltip-arrow-overlap);transform:rotate(180deg)}&[data-placement=right] svg{margin-right:var(--tooltip-arrow-overlap);transform:rotate(90deg)}&[data-placement=left] svg{margin-left:var(--tooltip-arrow-overlap);transform:rotate(-90deg)}}[data-theme=dark]{& .bui-Tooltip{background:var(--bui-bg-surface-2);box-shadow:none;border:1px solid var(--bui-gray-4)}& .bui-TooltipArrow{& svg path:first-child{fill:var(--bui-bg-surface-2)}& svg path:nth-child(2){fill:var(--bui-gray-4)}}}.bui-ScrollAreaRoot{box-sizing:border-box;width:100%}.bui-ScrollAreaViewport{overscroll-behavior:contain;height:100%}.bui-ScrollAreaContent{padding-block:.75rem;flex-direction:column;gap:1rem;padding-left:1rem;padding-right:1.5rem;display:flex}.bui-ScrollAreaScrollbar{background-color:var(--bui-scrollbar);opacity:0;border-radius:.375rem;justify-content:center;width:.25rem;margin:.5rem;transition:opacity .15s .3s;display:flex;&[data-hovering],&[data-scrolling]{opacity:1;transition-duration:75ms;transition-delay:0s}&:before{content:"";width:1.25rem;height:100%;position:absolute}}.bui-ScrollAreaThumb{border-radius:inherit;background-color:var(--bui-scrollbar-thumb);width:100%}.bui-Select[data-invalid]{& .bui-SelectTrigger{border-color:var(--bui-fg-danger)}}.bui-SelectTrigger{box-sizing:border-box;border-radius:var(--bui-radius-3);border:1px solid var(--bui-border);background-color:var(--bui-bg-surface-1);cursor:pointer;justify-content:space-between;align-items:center;gap:var(--bui-space-2);max-width:100%;transition:border-color .2s ease-in-out,outline-color .2s ease-in-out;display:flex;& svg{flex-shrink:0}&[data-size=small]{height:2rem;padding-inline:var(--bui-space-3)}&[data-size=medium]{height:3rem;padding-inline:var(--bui-space-4)}&[data-size=small] svg{width:1rem;height:1rem}&[data-size=medium] svg{width:1.25rem;height:1.25rem}&::placeholder{color:var(--bui-fg-secondary)}&:hover{border-color:var(--bui-border-hover)}&:focus-visible{border-color:var(--bui-border-pressed);outline:0}&[data-invalid]{border-color:var(--bui-fg-danger)}&[data-invalid]:hover,&[data-invalid]:focus-visible{border-width:2px}&[disabled]{cursor:not-allowed;border-color:var(--bui-border-disabled);color:var(--bui-fg-disabled)}&[disabled] .bui-SelectValue{color:var(--bui-fg-disabled)}&[data-popup-open] .bui-SelectIcon{transform:rotate(180deg)}}.bui-SelectValue{text-overflow:ellipsis;white-space:nowrap;width:100%;font-size:var(--bui-font-size-3);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);color:var(--bui-fg-primary);overflow:hidden;& .bui-SelectItemIndicator{display:none}&[disabled]{color:var(--bui-fg-disabled)}}.bui-SelectItem{width:var(--anchor-width);padding-block:var(--bui-space-2);padding-inline:var(--bui-space-4);color:var(--bui-fg-primary);border-radius:var(--bui-radius-3);cursor:pointer;user-select:none;font-size:var(--bui-font-size-3);align-items:center;gap:var(--bui-space-2);outline:none;grid-template-columns:1rem 1fr;grid-template-areas:"icon text";display:grid;position:relative;&[data-focused]{z-index:0;color:var(--bui-fg-primary);position:relative}&[data-focused]:before{content:"";z-index:-1;background-color:var(--bui-bg-tint-hover);border-radius:.25rem;position:absolute;inset-block:0;inset-inline:.25rem}&[data-disabled]{cursor:not-allowed;color:var(--bui-fg-disabled)}&[data-selected] .bui-SelectItemIndicator{opacity:1}}.bui-SelectItemIndicator{opacity:0;grid-area:icon;justify-content:center;align-items:center;transition:opacity .2s ease-in-out;display:flex}.bui-SelectItemLabel{flex:1;grid-area:text}.bui-Switch{align-items:center;gap:var(--bui-space-3);font-size:var(--bui-font-size-3);color:var(--bui-fg-primary);cursor:pointer;display:flex;position:relative;&[data-pressed] .bui-SwitchIndicator{&:before{background:var(--bui-fg-solid)}}&[data-selected]{& .bui-SwitchIndicator{background:var(--bui-bg-solid);&:before{background:var(--bui-fg-solid);transform:translate(100%)}}&[data-pressed]{& .indicator{background:var(--bui-gray-3)}}}&[data-focus-visible] .bui-SwitchIndicator{outline-offset:2px;outline:2px solid}}.bui-SwitchIndicator{background:var(--bui-gray-3);border:2px;border-radius:1.143rem;width:2rem;height:1.143rem;transition:all .2s;&:before{content:"";background:var(--bui-fg-solid);border-radius:16px;width:.857rem;height:.857rem;margin:.143rem;transition:all .2s;display:block}} \ No newline at end of file diff --git a/docs-ui/public/theme-spotify.css b/docs-ui/public/theme-spotify.css new file mode 100644 index 0000000000..0600e828d6 --- /dev/null +++ b/docs-ui/public/theme-spotify.css @@ -0,0 +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}}[data-theme=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=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 diff --git a/docs-ui/scripts/sync-css.js b/docs-ui/scripts/sync-css.js new file mode 100644 index 0000000000..58598e6eb3 --- /dev/null +++ b/docs-ui/scripts/sync-css.js @@ -0,0 +1,149 @@ +const fs = require('fs'); +const path = require('path'); +const { bundle } = require('lightningcss'); +const chokidar = require('chokidar'); + +// Configuration +const config = { + UIPath: '../../packages/ui', + publicPath: '../public', + files: [ + { + source: 'css/styles.css', + destination: 'theme-backstage.css', + name: 'Main Styles', + }, + { + source: '.storybook/themes/spotify.css', + destination: 'theme-spotify.css', + name: 'Spotify Theme', + }, + ], +}; + +class CSSSync { + constructor() { + this.UIPath = path.resolve(__dirname, config.UIPath); + this.publicPath = path.resolve(__dirname, config.publicPath); + this.isWatching = process.argv.includes('--watch'); + } + + async syncFile(fileConfig) { + const sourcePath = path.join(this.UIPath, fileConfig.source); + const destPath = path.join(this.publicPath, fileConfig.destination); + + try { + // Check if source file exists + if (!fs.existsSync(sourcePath)) { + console.warn(`⚠️ Source file not found: ${sourcePath}`); + return false; + } + + // Ensure destination directory exists + fs.mkdirSync(path.dirname(destPath), { recursive: true }); + + // Bundle and optimize CSS + const result = await bundle({ + filename: sourcePath, + minify: true, + }); + + // Write to destination + fs.writeFileSync(destPath, result.code); + + console.log( + `✅ ${fileConfig.name}: ${fileConfig.source} → ${fileConfig.destination}`, + ); + return true; + } catch (error) { + console.error(`❌ Error syncing ${fileConfig.name}:`, error.message); + return false; + } + } + + async syncAll() { + console.log('🔄 Syncing CSS files...\n'); + + let successCount = 0; + for (const fileConfig of config.files) { + if (await this.syncFile(fileConfig)) { + successCount++; + } + } + + console.log( + `\n✨ Synced ${successCount}/${config.files.length} CSS files successfully!`, + ); + + if (successCount > 0) { + console.log('\n📁 Available CSS files in public/:'); + config.files.forEach(file => { + const destPath = path.join(this.publicPath, file.destination); + if (fs.existsSync(destPath)) { + const stats = fs.statSync(destPath); + const size = (stats.size / 1024).toFixed(2); + console.log(` • ${file.destination} (${size} KB)`); + } + }); + } + } + + startWatching() { + console.log('👀 Watching for CSS changes...\n'); + + // Watch all source files + const watchPaths = config.files.map(file => + path.join(this.UIPath, file.source), + ); + + const watcher = chokidar.watch(watchPaths, { + ignored: /node_modules/, + persistent: true, + }); + + watcher.on('change', async filePath => { + console.log( + `\n🔄 Change detected: ${path.relative(this.UIPath, filePath)}`, + ); + + // Find which file changed and sync it + const fileConfig = config.files.find(file => + filePath.endsWith(file.source.replace(/\//g, path.sep)), + ); + + if (fileConfig) { + await this.syncFile(fileConfig); + } + }); + + watcher.on('error', error => console.error('❌ Watch error:', error)); + + // Handle process termination + process.on('SIGINT', () => { + console.log('\n👋 Stopping CSS sync...'); + watcher.close(); + process.exit(0); + }); + } + + async run() { + console.log('🎨 BUI CSS Sync Tool\n'); + console.log(`📂 BUI path: ${this.UIPath}`); + console.log(`📂 Public path: ${this.publicPath}\n`); + + // Initial sync + await this.syncAll(); + + // Watch for changes if requested + if (this.isWatching) { + this.startWatching(); + } + } +} + +// Run the sync tool +const cssSync = new CSSSync(); +cssSync.run().catch(error => { + console.error('❌ CSS Sync failed:', error); + process.exit(1); +}); diff --git a/canon-docs/src/app/(docs)/about/page.mdx b/docs-ui/src/app/about/page.mdx similarity index 62% rename from canon-docs/src/app/(docs)/about/page.mdx rename to docs-ui/src/app/about/page.mdx index a4c16ee79e..2c87a3d03e 100644 --- a/canon-docs/src/app/(docs)/about/page.mdx +++ b/docs-ui/src/app/about/page.mdx @@ -1,7 +1,7 @@ -# About Canon +# About Backstage UI -Canon is a design system created specifically for Backstage, built with React, TypeScript, and vanilla CSS. -This open-source library is hosted in the Backstage monorepo. While it can be used in other projects, Canon +Backstage UI is a design system created specifically for Backstage, built with React, TypeScript, and vanilla CSS. +This open-source library is hosted in the Backstage monorepo. While it can be used in other projects, Backstage UI is designed to deliver a consistent, accessible, and extensible experience tailored to Backstage users. ## Philosophy @@ -17,16 +17,16 @@ and flexible theming system. ## Team -Canon is designed and maintained primarily by Spotify's Backstage team, leveraging Spotify's expertise in +Backstage UI is designed and maintained primarily by Spotify's Backstage team, leveraging Spotify's expertise in crafting high-quality design and technology. Drawing from our experience in building reliable and intuitive user experiences for the music industry, we've created a design system that looks great and works seamlessly. ## Community -Canon is an open-source project and we welcome contributions from the community. If you are interested in -contributing to Canon, please read our [contributing guide](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) +Backstage UI is an open-source project and we welcome contributions from the community. If you are interested in +contributing to Backstage UI, please read our [contributing guide](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) and our [code of conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md). ## License -Canon is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/backstage/backstage/blob/master/LICENSE) file for more details. +Backstage UI is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/backstage/backstage/blob/master/LICENSE) file for more details. diff --git a/canon-docs/src/app/(docs)/changelog/page.mdx b/docs-ui/src/app/changelog/page.mdx similarity index 75% rename from canon-docs/src/app/(docs)/changelog/page.mdx rename to docs-ui/src/app/changelog/page.mdx index 7cc0b2bf3e..bbeaa98458 100644 --- a/canon-docs/src/app/(docs)/changelog/page.mdx +++ b/docs-ui/src/app/changelog/page.mdx @@ -6,8 +6,8 @@ import { Changelog } from '@/components/Changelog'; ## Version 0.1.0 -We're excited to share the initial release of Canon 💚 In this first alpha version, +We're excited to share the initial release of Backstage UI 💚 In this first alpha version, you'll find the foundation of our design system: a set of versatile layout components -and a handful of essential atomic elements to help you get started. While Canon is +and a handful of essential atomic elements to help you get started. While Backstage UI is still in its early stages, it's ready for exploration and we'd love for you to give it a try and share your feedback. diff --git a/canon-docs/src/app/(docs)/components/[slug]/page.tsx b/docs-ui/src/app/components/[slug]/page.tsx similarity index 100% rename from canon-docs/src/app/(docs)/components/[slug]/page.tsx rename to docs-ui/src/app/components/[slug]/page.tsx diff --git a/canon-docs/src/app/icon.svg b/docs-ui/src/app/icon.svg similarity index 100% rename from canon-docs/src/app/icon.svg rename to docs-ui/src/app/icon.svg diff --git a/docs-ui/src/app/layout.module.css b/docs-ui/src/app/layout.module.css new file mode 100644 index 0000000000..7399fc2485 --- /dev/null +++ b/docs-ui/src/app/layout.module.css @@ -0,0 +1,28 @@ +.container { + position: relative; + z-index: 20; + width: calc(100% - 64px); + margin-inline: 0 16px; + margin-left: 32px; + margin-right: 32px; + margin-top: 112px; + margin-bottom: 48px; + padding-inline: 40px; + padding-block: 48px; + background-color: var(--panel); + border-radius: 0.5rem; +} + +.content { + width: 100%; + max-width: 960px; + margin: 0 auto; +} + +@media (min-width: 768px) { + .container { + width: calc(100% - 332px - 40px); + margin-left: 332px; + margin-right: 40px; + } +} diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx new file mode 100644 index 0000000000..58decbf22b --- /dev/null +++ b/docs-ui/src/app/layout.tsx @@ -0,0 +1,62 @@ +import type { Metadata } from 'next'; +import { Sidebar } from '../components/Sidebar'; +import { Toolbar } from '@/components/Toolbar'; +import { Providers } from './providers'; +import { CustomTheme } from '@/components/CustomTheme'; +import styles from './layout.module.css'; + +import '../css/globals.css'; +import '/public/theme-backstage.css'; +import '/public/theme-spotify.css'; + +export const metadata: Metadata = { + title: 'Backstage UI', + description: 'UI library for Backstage', + metadataBase: new URL('https://ui.backstage.io'), +}; + +async function getLatestPackageVersion(): Promise { + try { + const response = await fetch('https://registry.npmjs.org/@backstage/ui', { + next: { revalidate: 3600 }, // Cache for 1 hour + }); + + if (!response.ok) { + throw new Error('Failed to fetch package info'); + } + + const data = await response.json(); + return data['dist-tags']?.latest; + } catch (error) { + console.error('Error fetching package version:', error); + return '0.0.0'; + } +} + +export default async function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + const packageVersion = await getLatestPackageVersion(); + + return ( + + + + + +
+
{children}
+
+ +
+ + + ); +} diff --git a/canon-docs/src/app/opengraph-image.jpg b/docs-ui/src/app/opengraph-image.jpg similarity index 100% rename from canon-docs/src/app/opengraph-image.jpg rename to docs-ui/src/app/opengraph-image.jpg diff --git a/canon-docs/src/app/(docs)/page.mdx b/docs-ui/src/app/page.mdx similarity index 64% rename from canon-docs/src/app/(docs)/page.mdx rename to docs-ui/src/app/page.mdx index 862127ec7b..27d7bc66d4 100644 --- a/canon-docs/src/app/(docs)/page.mdx +++ b/docs-ui/src/app/page.mdx @@ -1,11 +1,8 @@ import { CodeBlock } from '@/components/CodeBlock'; - +# Backstage UI -Welcome to the Canon, the new design library for Backstage plugins. This +Welcome to the Backstage UI, the new design library for Backstage plugins. This project is still under active development but we will make sure to document the API as we go. We are aiming to improve the general UI of Backstage and plugins across Backstage. This new library will take time to build but we are @@ -13,18 +10,18 @@ building it incrementally with not conflict with the existing theming system. ## Installation -### 1. Install canon +### 1. Install Backstage UI -Install Canon using a package manager. +Install Backstage UI using a package manager. - + ### 2. Import the css files Import the global CSS file at the root of your application. ```tsx -import '@backstage/canon/css/styles.css'; +import '@backstage/ui/css/styles.css'; ``` ### 3. Start building ✨ @@ -32,7 +29,7 @@ import '@backstage/canon/css/styles.css'; Now you can start building your plugin using the new design system. ```tsx -import { Flex, Button, Text } from '@backstage/canon'; +import { Flex, Button, Text } from '@backstage/ui'; Hello World @@ -40,10 +37,6 @@ import { Flex, Button, Text } from '@backstage/canon'; ; ``` -## Roadmap - -You can check our roadmap [on GitHub](https://github.com/orgs/backstage/projects/10). We'll do our best to keep you updated on the progress. - ## Next steps Now that you have the basics down, you can start building your plugin using the new design system. diff --git a/canon-docs/src/app/providers.tsx b/docs-ui/src/app/providers.tsx similarity index 100% rename from canon-docs/src/app/providers.tsx rename to docs-ui/src/app/providers.tsx diff --git a/canon-docs/src/app/(docs)/theme/iconography/page.mdx b/docs-ui/src/app/theme/iconography/page.mdx similarity index 100% rename from canon-docs/src/app/(docs)/theme/iconography/page.mdx rename to docs-ui/src/app/theme/iconography/page.mdx diff --git a/canon-docs/src/app/(docs)/theme/layout/page.mdx b/docs-ui/src/app/theme/layout/page.mdx similarity index 94% rename from canon-docs/src/app/(docs)/theme/layout/page.mdx rename to docs-ui/src/app/theme/layout/page.mdx index b069082b04..3c3b998490 100644 --- a/canon-docs/src/app/(docs)/theme/layout/page.mdx +++ b/docs-ui/src/app/theme/layout/page.mdx @@ -3,7 +3,7 @@ import { CodeBlock } from '@/components/CodeBlock'; # Layout -Canon is made for extensibility. We built this library to make it easy for any +Backstage UI is made for extensibility. We built this library to make it easy for any Backstage plugin creator to be able to build their ideas at speed ensuring consistency across the rest of your ecosystem. Each component is designed to be editable to match your need but sometimes you want to have more control diff --git a/canon-docs/src/app/(docs)/theme/responsive/page.mdx b/docs-ui/src/app/theme/responsive/page.mdx similarity index 94% rename from canon-docs/src/app/(docs)/theme/responsive/page.mdx rename to docs-ui/src/app/theme/responsive/page.mdx index 7eb4411333..9d37b1329f 100644 --- a/canon-docs/src/app/(docs)/theme/responsive/page.mdx +++ b/docs-ui/src/app/theme/responsive/page.mdx @@ -4,7 +4,7 @@ import { CodeBlock } from '@/components/CodeBlock'; # Responsive -Canon is built on a responsive design system, meaning that the components are +Backstage UI is built on a responsive design system, meaning that the components are designed to adapt to different screen sizes. By default we offer a set of breakpoints that you can use to create responsive components. @@ -90,7 +90,7 @@ breakpoints that you can use to create responsive components. ## Responsive components -Canon components are designed to be responsive, meaning that they will adapt +Backstage UI components are designed to be responsive, meaning that they will adapt to different screen sizes. Not every component is responsive, but the ones that are will have a prop to control the responsive behavior. diff --git a/canon-docs/src/app/(docs)/theme/theming/page.mdx b/docs-ui/src/app/theme/theming/page.mdx similarity index 73% rename from canon-docs/src/app/(docs)/theme/theming/page.mdx rename to docs-ui/src/app/theme/theming/page.mdx index ed7f801db0..5205690d0b 100644 --- a/canon-docs/src/app/(docs)/theme/theming/page.mdx +++ b/docs-ui/src/app/theme/theming/page.mdx @@ -5,7 +5,7 @@ import { customTheme } from '@/snippets/code-snippets'; # Theming -Canon's theming is built entirely on CSS, without relying on any CSS-in-JS libraries. +Backstage UI theming is built entirely on CSS, without relying on any CSS-in-JS libraries. At its core, it provides a solid default theme that is easily customizable using a comprehensive set of CSS variables. Additionally, it enables anyone to adapt the design to their specific needs. Each component comes with fixed class names, making customization @@ -13,7 +13,7 @@ even more straightforward. ## Light & Dark modes -By default, Canon supports both light and dark modes using the `data-theme` attribute. +By default, Backstage UI supports both light and dark modes using the `data-theme` attribute. The light theme is applied by default if no `data-theme` attribute is specified. To create a custom theme, you'll need to define both light and dark modes as outlined below. If only one mode is defined, the other will fall back to the default theme. @@ -31,7 +31,7 @@ Here's an example of how your theme.css file should look like: ## CSS class name structure -All Canon components come with a set of CSS classes that you can use to style them. To make it +All Backstage UI components come with a set of CSS classes that you can use to style them. To make it easier to identify the class name you can use, we use a specific structure for the class names. -Every component has a unique prefix `.canon-` followed by the component name. Component props +Every component has a unique prefix `.bui-` followed by the component name. Component props are represented using the `data-` attribute. That way, class names are easily identifiable. ## Available CSS variables @@ -58,7 +58,7 @@ These colors are used for special purposes like ring, scrollbar, ... - --canon-black + --bui-black Pure black color. This one should be the same in light and dark themes. @@ -66,7 +66,7 @@ These colors are used for special purposes like ring, scrollbar, ... - --canon-white + --bui-white Pure white color. This one should be the same in light and dark themes. @@ -74,49 +74,49 @@ These colors are used for special purposes like ring, scrollbar, ... - --canon-gray-1 + --bui-gray-1 You can use these mostly for backgrounds colors. - --canon-gray-2 + --bui-gray-2 You can use these mostly for backgrounds colors. - --canon-gray-3 + --bui-gray-3 You can use these mostly for backgrounds colors. - --canon-gray-4 + --bui-gray-4 You can use these mostly for backgrounds colors. - --canon-gray-5 + --bui-gray-5 You can use these mostly for backgrounds colors. - --canon-gray-6 + --bui-gray-6 You can use these mostly for backgrounds colors. - --canon-gray-7 + --bui-gray-7 You can use these mostly for backgrounds colors. - --canon-gray-8 + --bui-gray-8 You can use these mostly for backgrounds colors. @@ -126,7 +126,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. `--canon-bg` should mostly use as the main background +single elevated background for panels. `--bui-bg` should mostly use as the main background color of your app. @@ -139,85 +139,85 @@ color of your app. - --canon-bg + --bui-bg The background color of your Backstage instance. - --canon-bg-surface-1 + --bui-bg-surface-1 Use for any panels or elevated surfaces. - --canon-bg-surface-2 + --bui-bg-surface-2 Use for any panels or elevated surfaces. - --canon-bg-solid + --bui-bg-solid Used for solid background colors. - --canon-bg-solid-hover + --bui-bg-solid-hover Used for solid background colors when hovered. - --canon-bg-solid-pressed + --bui-bg-solid-pressed Used for solid background colors when pressed. - --canon-bg-solid-disabled + --bui-bg-solid-disabled Used for solid background colors when disabled. - --canon-bg-tint + --bui-bg-tint Used for tint background colors. - --canon-bg-tint-hover + --bui-bg-tint-hover Used for tint background colors when hovered. - --canon-bg-tint-focus + --bui-bg-tint-focus Used for tint background colors when active. - --canon-bg-tint-disabled + --bui-bg-tint-disabled Used for tint background colors when disabled. - --canon-bg-danger + --bui-bg-danger Used to show errors information. - --canon-bg-warning + --bui-bg-warning Used to show warnings information. - --canon-bg-success + --bui-bg-success Used to show success information. @@ -240,7 +240,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-primary + --bui-fg-primary It should be used on top of main background surfaces. @@ -248,7 +248,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-secondary + --bui-fg-secondary It should be used on top of main background surfaces. @@ -256,7 +256,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-link + --bui-fg-link It should be used on top of main background surfaces. @@ -264,7 +264,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-link-hover + --bui-fg-link-hover It should be used on top of main background surfaces. @@ -272,7 +272,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-disabled + --bui-fg-disabled It should be used on top of main background surfaces. @@ -280,7 +280,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-solid + --bui-fg-solid It should be used on top of solid background colors. @@ -288,7 +288,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-tint + --bui-fg-tint It should be used on top of tint background colors. @@ -296,7 +296,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-tint-disabled + --bui-fg-tint-disabled It should be used on top of tint background colors when disabled. @@ -304,7 +304,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-danger + --bui-fg-danger It should be used on top of danger background colors. @@ -312,7 +312,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-warning + --bui-fg-warning It should be used on top of warning background colors. @@ -320,7 +320,7 @@ are prefixed with `fg` to make it easier to identify. - --canon-fg-success + --bui-fg-success It should be used on top of success background colors. @@ -344,15 +344,13 @@ low contrast to help as a separator with the different background colors. - --canon-border - - - It should be used on top of `--canon-bg-surface-1`. + --bui-border + It should be used on top of `--bui-bg-surface-1`. - --canon-border-hover + --bui-border-hover Used when the component is interactive and hovered. @@ -360,7 +358,7 @@ low contrast to help as a separator with the different background colors. - --canon-border-pressed + --bui-border-pressed Used when the component is interactive and focused. @@ -368,27 +366,27 @@ low contrast to help as a separator with the different background colors. - --canon-border-disabled + --bui-border-disabled Used when the component is disabled. - --canon-border-danger + --bui-border-danger - It should be used on top of `--canon-bg-danger`. + It should be used on top of `--bui-bg-danger`. - --canon-border-warning + --bui-border-warning - It should be used on top of `--canon-bg-warning`. + It should be used on top of `--bui-bg-warning`. - --canon-border-success + --bui-border-success - It should be used on top of `--canon-bg-success`. + It should be used on top of `--bui-bg-success`. @@ -407,19 +405,19 @@ These colors are used for special purposes like ring, scrollbar, ... - --canon-ring + --bui-ring The color of the ring. - --canon-scrollbar + --bui-scrollbar The color of the scrollbar. - --canon-scrollbar-thumb + --bui-scrollbar-thumb The color of the scrollbar thumb. @@ -428,7 +426,7 @@ These colors are used for special purposes like ring, scrollbar, ... ### Font families -We have two fonts that we use across Canon. The first one is the sans-serif +We have two fonts that we use across Backstage UI. The first one is the sans-serif font that we use for the body of the application. The second one is the monospace font that we use for code blocks and tables. @@ -442,13 +440,13 @@ monospace font that we use for code blocks and tables. - --canon-font-regular + --bui-font-regular The sans-serif font for the theme. - --canon-font-mono + --bui-font-mono The monospace font for the theme. @@ -457,7 +455,7 @@ monospace font that we use for code blocks and tables. ### Font weights -We have two font weights that we use across Canon. Regular or Bold. +We have two font weights that we use across Backstage UI. Regular or Bold. @@ -469,13 +467,13 @@ We have two font weights that we use across Canon. Regular or Bold. - --canon-font-weight-regular + --bui-font-weight-regular The regular font weight for the theme. - --canon-font-weight-bold + --bui-font-weight-bold The bold font weight for the theme. @@ -484,12 +482,12 @@ We have two font weights that we use across Canon. Regular or Bold. ### Spacing -We built a spacing system based on a single value `--canon-space`. This value is +We built a spacing system based on a single value `--bui-space`. This value is used to calculate the spacing for all the components. By default if you would like to increase or decrease the spacing between your components you can do it simply by updating -`--canon-space` and it will apply to all spacing values. +`--bui-space` and it will apply to all spacing values. -`--canon-space` is not used directly in any components but serve as an easy way to +`--bui-space` is not used directly in any components but serve as an easy way to calculate the other values. @@ -502,7 +500,7 @@ calculate the other values. - --canon-space + --bui-space The base unit for the spacing system. Default value is `0.25rem`. @@ -524,99 +522,99 @@ tokens for pretty much each spacing properties like padding, margin, gaps, ... - --canon-space-0_5 + --bui-space-0_5 - Base unit (`--canon-space`) times 0.5. + Base unit (`--bui-space`) times 0.5. - --canon-space-1 + --bui-space-1 - Base unit (`--canon-space`). + Base unit (`--bui-space`). - --canon-space-1_5 + --bui-space-1_5 - Base unit (`--canon-space`) times 1.5. + Base unit (`--bui-space`) times 1.5. - --canon-space-2 + --bui-space-2 - Base unit (`--canon-space`) times 2. + Base unit (`--bui-space`) times 2. - --canon-space-3 + --bui-space-3 - Base unit (`--canon-space`) times 3. + Base unit (`--bui-space`) times 3. - --canon-space-4 + --bui-space-4 - Base unit (`--canon-space`) times 4. + Base unit (`--bui-space`) times 4. - --canon-space-5 + --bui-space-5 - Base unit (`--canon-space`) times 5. + Base unit (`--bui-space`) times 5. - --canon-space-6 + --bui-space-6 - Base unit (`--canon-space`) times 6. + Base unit (`--bui-space`) times 6. - --canon-space-7 + --bui-space-7 - Base unit (`--canon-space`) times 7. + Base unit (`--bui-space`) times 7. - --canon-space-8 + --bui-space-8 - Base unit (`--canon-space`) times 8. + Base unit (`--bui-space`) times 8. - --canon-space-9 + --bui-space-9 - Base unit (`--canon-space`) times 9. + Base unit (`--bui-space`) times 9. - --canon-space-10 + --bui-space-10 - Base unit (`--canon-space`) times 10. + Base unit (`--bui-space`) times 10. - --canon-space-11 + --bui-space-11 - Base unit (`--canon-space`) times 11. + Base unit (`--bui-space`) times 11. - --canon-space-12 + --bui-space-12 - Base unit (`--canon-space`) times 12. + Base unit (`--bui-space`) times 12. - --canon-space-13 + --bui-space-13 - Base unit (`--canon-space`) times 13. + Base unit (`--bui-space`) times 13. - --canon-space-14 + --bui-space-14 - Base unit (`--canon-space`) times 14. + Base unit (`--bui-space`) times 14. @@ -635,7 +633,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-1 + --bui-radius-1 The radius of the component. Default value is `0.125rem`. @@ -643,7 +641,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-2 + --bui-radius-2 The radius of the component. Default value is `0.25rem`. @@ -651,7 +649,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-3 + --bui-radius-3 The radius of the component. Default value is `0.5rem`. @@ -659,7 +657,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-4 + --bui-radius-4 The radius of the component. Default value is `0.75rem`. @@ -667,7 +665,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-5 + --bui-radius-5 The radius of the component. Default value is `1rem`. @@ -675,7 +673,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-6 + --bui-radius-6 The radius of the component. Default value is `1.25rem`. @@ -683,7 +681,7 @@ We use a radius system to make sure that the components have a consistent look a - --canon-radius-full + --bui-radius-full The radius of the component. Default value is `9999px`. diff --git a/canon-docs/src/app/(docs)/theme/typography/page.mdx b/docs-ui/src/app/theme/typography/page.mdx similarity index 93% rename from canon-docs/src/app/(docs)/theme/typography/page.mdx rename to docs-ui/src/app/theme/typography/page.mdx index 98a342bc91..31c55b8e25 100644 --- a/canon-docs/src/app/(docs)/theme/typography/page.mdx +++ b/docs-ui/src/app/theme/typography/page.mdx @@ -3,7 +3,7 @@ import { Snippet } from '@/components/Snippet'; # Typography -Canon offers a suite of typography components designed to seamlessly align +Backstage UI offers a suite of typography components designed to seamlessly align with the rest of your Backstage instance. While you can customize their appearance to match your brand, the underlying API remains consistent and unchanged. Each component is built on a responsive structure, allowing you to @@ -31,7 +31,7 @@ component](?path=/docs/components-heading--docs). ## Text -Canon provides four distinct text variants, each offering different font sizes +Backstage UI provides four distinct text variants, each offering different font sizes carefully designed to cover the majority of use cases. These variants are versatile and can be paired with regular and bold of font weights. You can use the [Text component](?path=/docs/components-text--docs) to add text to your diff --git a/canon-docs/src/components/Banner/Banner.tsx b/docs-ui/src/components/Banner/Banner.tsx similarity index 100% rename from canon-docs/src/components/Banner/Banner.tsx rename to docs-ui/src/components/Banner/Banner.tsx diff --git a/canon-docs/src/components/Banner/index.ts b/docs-ui/src/components/Banner/index.ts similarity index 100% rename from canon-docs/src/components/Banner/index.ts rename to docs-ui/src/components/Banner/index.ts diff --git a/canon-docs/src/components/Banner/styles.module.css b/docs-ui/src/components/Banner/styles.module.css similarity index 100% rename from canon-docs/src/components/Banner/styles.module.css rename to docs-ui/src/components/Banner/styles.module.css diff --git a/docs-ui/src/components/Changelog/index.tsx b/docs-ui/src/components/Changelog/index.tsx new file mode 100644 index 0000000000..224e23d668 --- /dev/null +++ b/docs-ui/src/components/Changelog/index.tsx @@ -0,0 +1,75 @@ +import { changelog } from '@/utils/changelog'; +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; + +export function Changelog() { + // Group changelog entries by version + const groupedChangelog = changelog.reduce((acc, entry) => { + if (!acc[entry.version]) { + acc[entry.version] = []; + } + acc[entry.version].push(entry); + return acc; + }, {} as Record); + + // Sort versions in descending order + const sortedVersions = Object.keys(groupedChangelog).sort((a, b) => + b.localeCompare(a), + ); + + const content = sortedVersions + .map(version => { + const entries = groupedChangelog[version]; + + // Group entries by bump type + const groupedByBump = entries.reduce((acc, entry) => { + const bumpType = entry.type || 'other'; + if (!acc[bumpType]) { + acc[bumpType] = []; + } + acc[bumpType].push(entry); + return acc; + }, {} as Record); + + // Define the order of bump types + const bumpOrder = ['breaking', 'new', 'fix', 'other']; + + const bumpSections = bumpOrder + .filter(bumpType => groupedByBump[bumpType]?.length > 0) + .map(bumpType => { + const bumpEntries = groupedByBump[bumpType]; + let sectionTitle = 'Other Changes'; + if (bumpType === 'breaking') { + sectionTitle = 'Breaking Changes'; + } else if (bumpType === 'new') { + sectionTitle = 'New Features'; + } else if (bumpType === 'fix') { + sectionTitle = 'Bug Fixes'; + } + + return `### ${sectionTitle} + + ${bumpEntries + .map(e => { + const prs = + e.prs.length > 0 && + e.prs + .map( + pr => + `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, + ) + .join(', '); + return `- ${e.description} ${prs}`; + }) + .join('\n')}`; + }) + .join('\n\n'); + + return `## Version ${version} + + ${bumpSections}`; + }) + .join('\n'); + + return ; +} diff --git a/docs-ui/src/components/ChangelogComponent/index.tsx b/docs-ui/src/components/ChangelogComponent/index.tsx new file mode 100644 index 0000000000..f8832b0731 --- /dev/null +++ b/docs-ui/src/components/ChangelogComponent/index.tsx @@ -0,0 +1,32 @@ +import { changelog } from '@/utils/changelog'; +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import type { Component } from '@/utils/changelog'; + +export const ChangelogComponent = ({ component }: { component: Component }) => { + const componentChangelog = changelog.filter(c => + c.components.includes(component), + ); + + return ( + { + const prs = + change.prs.length > 0 && + change.prs + .map( + pr => + `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, + ) + .join(', '); + return `- \`${change.version}\` - ${change.description} ${prs}`; + }) + .join('\n')}`} + /> + ); +}; diff --git a/canon-docs/src/components/Chip/Chip.tsx b/docs-ui/src/components/Chip/Chip.tsx similarity index 100% rename from canon-docs/src/components/Chip/Chip.tsx rename to docs-ui/src/components/Chip/Chip.tsx diff --git a/canon-docs/src/components/Chip/index.ts b/docs-ui/src/components/Chip/index.ts similarity index 100% rename from canon-docs/src/components/Chip/index.ts rename to docs-ui/src/components/Chip/index.ts diff --git a/canon-docs/src/components/Chip/styles.module.css b/docs-ui/src/components/Chip/styles.module.css similarity index 89% rename from canon-docs/src/components/Chip/styles.module.css rename to docs-ui/src/components/Chip/styles.module.css index b96899e6d5..9b80b937d5 100644 --- a/canon-docs/src/components/Chip/styles.module.css +++ b/docs-ui/src/components/Chip/styles.module.css @@ -9,7 +9,6 @@ margin-right: 4px; background-color: #f0f0f0; color: #5d5d5d; - transition: background-color 0.2s ease-in-out; } .head { diff --git a/canon-docs/src/components/CodeBlock/client.tsx b/docs-ui/src/components/CodeBlock/client.tsx similarity index 92% rename from canon-docs/src/components/CodeBlock/client.tsx rename to docs-ui/src/components/CodeBlock/client.tsx index 6626c4ce6e..b4ee98f2f3 100644 --- a/canon-docs/src/components/CodeBlock/client.tsx +++ b/docs-ui/src/components/CodeBlock/client.tsx @@ -1,7 +1,7 @@ 'use client'; import { CodeBlockProps } from '.'; -import { Text } from '@backstage/canon'; +import { Text } from '@backstage/ui'; import styles from './styles.module.css'; import parse from 'html-react-parser'; diff --git a/canon-docs/src/components/CodeBlock/index.tsx b/docs-ui/src/components/CodeBlock/index.tsx similarity index 100% rename from canon-docs/src/components/CodeBlock/index.tsx rename to docs-ui/src/components/CodeBlock/index.tsx diff --git a/canon-docs/src/components/CodeBlock/styles.module.css b/docs-ui/src/components/CodeBlock/styles.module.css similarity index 81% rename from canon-docs/src/components/CodeBlock/styles.module.css rename to docs-ui/src/components/CodeBlock/styles.module.css index 8b17c11b86..03ec72d6c4 100644 --- a/canon-docs/src/components/CodeBlock/styles.module.css +++ b/docs-ui/src/components/CodeBlock/styles.module.css @@ -4,9 +4,8 @@ position: relative; background: transparent; overflow-x: auto; - font-family: var(--canon-font-monospace); + font-family: var(--font-mono); background-color: #fff; - transition: background-color 0.2s ease-in-out; margin-bottom: 1rem; } diff --git a/canon-docs/src/components/Columns/Columns.tsx b/docs-ui/src/components/Columns/Columns.tsx similarity index 100% rename from canon-docs/src/components/Columns/Columns.tsx rename to docs-ui/src/components/Columns/Columns.tsx diff --git a/canon-docs/src/components/Columns/index.ts b/docs-ui/src/components/Columns/index.ts similarity index 100% rename from canon-docs/src/components/Columns/index.ts rename to docs-ui/src/components/Columns/index.ts diff --git a/canon-docs/src/components/Columns/styles.css b/docs-ui/src/components/Columns/styles.css similarity index 100% rename from canon-docs/src/components/Columns/styles.css rename to docs-ui/src/components/Columns/styles.css diff --git a/canon-docs/src/components/CustomTheme/customTheme.tsx b/docs-ui/src/components/CustomTheme/customTheme.tsx similarity index 97% rename from canon-docs/src/components/CustomTheme/customTheme.tsx rename to docs-ui/src/components/CustomTheme/customTheme.tsx index 66b4afc47c..c70d59173a 100644 --- a/canon-docs/src/components/CustomTheme/customTheme.tsx +++ b/docs-ui/src/components/CustomTheme/customTheme.tsx @@ -6,18 +6,18 @@ import { sass } from '@codemirror/lang-sass'; import styles from './styles.module.css'; import { usePlayground } from '@/utils/playground-context'; import { AnimatePresence, motion } from 'motion/react'; -import { Icon } from '../../../../packages/canon'; +import { Icon } from '../../../../packages/ui'; import { createTheme } from '@uiw/codemirror-themes'; import { tags as t } from '@lezer/highlight'; const defaultTheme = `:root { - --canon-bg-accent: #000; + --bui-bg-solid: #000; }`; const myTheme = createTheme({ theme: 'light', settings: { - background: 'var(--canon-bg-surface-1)', + background: 'var(--surface-1)', backgroundImage: '', foreground: '#6182B8', caret: '#5d00ff', diff --git a/canon-docs/src/components/CustomTheme/index.ts b/docs-ui/src/components/CustomTheme/index.ts similarity index 100% rename from canon-docs/src/components/CustomTheme/index.ts rename to docs-ui/src/components/CustomTheme/index.ts diff --git a/canon-docs/src/components/CustomTheme/styles.module.css b/docs-ui/src/components/CustomTheme/styles.module.css similarity index 98% rename from canon-docs/src/components/CustomTheme/styles.module.css rename to docs-ui/src/components/CustomTheme/styles.module.css index 3f0a5eb14e..05604c48be 100644 --- a/canon-docs/src/components/CustomTheme/styles.module.css +++ b/docs-ui/src/components/CustomTheme/styles.module.css @@ -1,5 +1,6 @@ .container { position: fixed; + z-index: 100; bottom: 16px; right: 16px; width: 240px; diff --git a/canon-docs/src/components/DecorativeBox/index.tsx b/docs-ui/src/components/DecorativeBox/index.tsx similarity index 100% rename from canon-docs/src/components/DecorativeBox/index.tsx rename to docs-ui/src/components/DecorativeBox/index.tsx diff --git a/canon-docs/src/components/DecorativeBox/styles.module.css b/docs-ui/src/components/DecorativeBox/styles.module.css similarity index 100% rename from canon-docs/src/components/DecorativeBox/styles.module.css rename to docs-ui/src/components/DecorativeBox/styles.module.css diff --git a/canon-docs/src/components/HeadlessBanners/BaseUI.tsx b/docs-ui/src/components/HeadlessBanners/BaseUI.tsx similarity index 95% rename from canon-docs/src/components/HeadlessBanners/BaseUI.tsx rename to docs-ui/src/components/HeadlessBanners/BaseUI.tsx index 86a0e1ecbd..69f8e41df0 100644 --- a/canon-docs/src/components/HeadlessBanners/BaseUI.tsx +++ b/docs-ui/src/components/HeadlessBanners/BaseUI.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Icon, Text } from '../../../../packages/canon'; +import { Icon, Text } from '../../../../packages/ui'; import styles from './styles.module.css'; interface BaseUIProps { diff --git a/canon-docs/src/components/HeadlessBanners/styles.module.css b/docs-ui/src/components/HeadlessBanners/styles.module.css similarity index 60% rename from canon-docs/src/components/HeadlessBanners/styles.module.css rename to docs-ui/src/components/HeadlessBanners/styles.module.css index c87787634e..384327c394 100644 --- a/canon-docs/src/components/HeadlessBanners/styles.module.css +++ b/docs-ui/src/components/HeadlessBanners/styles.module.css @@ -1,16 +1,16 @@ .container { display: flex; background-color: var(--panel); - padding: var(--canon-space-6); - border-radius: var(--canon-radius-2); + padding: 1.5rem; + border-radius: 0.25rem; border: 1px solid var(--border); - margin-bottom: var(--canon-space-6); - gap: var(--canon-space-6); + margin-bottom: 1.5rem; + gap: 1.5rem; transition: background-color 0.2s ease-in-out; } .icon path { - fill: var(--canon-fg-primary); + fill: var(--primary); } .content { @@ -31,12 +31,12 @@ cursor: pointer; background-color: var(--bg); border: 1px solid var(--border); - border-radius: var(--canon-radius-2); - padding: 0 var(--canon-space-3); + border-radius: 0.25rem; + padding: 0 0.75rem; height: 28px; border-radius: 100px; - margin-top: var(--canon-space-3); - font-size: var(--canon-font-size-3); + margin-top: 0.75rem; + font-size: 0.875rem; color: var(--primary); - gap: var(--canon-space-2); + gap: 0.5rem; } diff --git a/canon-docs/src/components/IconLibrary/IconLibrary.tsx b/docs-ui/src/components/IconLibrary/IconLibrary.tsx similarity index 78% rename from canon-docs/src/components/IconLibrary/IconLibrary.tsx rename to docs-ui/src/components/IconLibrary/IconLibrary.tsx index 331dd3f5d0..bad51e62bf 100644 --- a/canon-docs/src/components/IconLibrary/IconLibrary.tsx +++ b/docs-ui/src/components/IconLibrary/IconLibrary.tsx @@ -1,7 +1,7 @@ 'use client'; -import { Text, Icon, icons } from '../../../../packages/canon'; -import type { IconNames } from '../../../../packages/canon'; +import { Text, Icon, icons } from '../../../../packages/ui'; +import type { IconNames } from '../../../../packages/ui'; import styles from './styles.module.css'; export const IconLibrary = () => { diff --git a/canon-docs/src/components/IconLibrary/index.ts b/docs-ui/src/components/IconLibrary/index.ts similarity index 100% rename from canon-docs/src/components/IconLibrary/index.ts rename to docs-ui/src/components/IconLibrary/index.ts diff --git a/canon-docs/src/components/IconLibrary/styles.module.css b/docs-ui/src/components/IconLibrary/styles.module.css similarity index 100% rename from canon-docs/src/components/IconLibrary/styles.module.css rename to docs-ui/src/components/IconLibrary/styles.module.css diff --git a/canon-docs/src/components/LayoutComponents/LayoutComponents.module.css b/docs-ui/src/components/LayoutComponents/LayoutComponents.module.css similarity index 100% rename from canon-docs/src/components/LayoutComponents/LayoutComponents.module.css rename to docs-ui/src/components/LayoutComponents/LayoutComponents.module.css diff --git a/canon-docs/src/components/LayoutComponents/LayoutComponents.tsx b/docs-ui/src/components/LayoutComponents/LayoutComponents.tsx similarity index 100% rename from canon-docs/src/components/LayoutComponents/LayoutComponents.tsx rename to docs-ui/src/components/LayoutComponents/LayoutComponents.tsx diff --git a/canon-docs/src/components/LayoutComponents/index.ts b/docs-ui/src/components/LayoutComponents/index.ts similarity index 100% rename from canon-docs/src/components/LayoutComponents/index.ts rename to docs-ui/src/components/LayoutComponents/index.ts diff --git a/canon-docs/src/components/LayoutComponents/svgs/box.tsx b/docs-ui/src/components/LayoutComponents/svgs/box.tsx similarity index 100% rename from canon-docs/src/components/LayoutComponents/svgs/box.tsx rename to docs-ui/src/components/LayoutComponents/svgs/box.tsx diff --git a/canon-docs/src/components/LayoutComponents/svgs/container.tsx b/docs-ui/src/components/LayoutComponents/svgs/container.tsx similarity index 100% rename from canon-docs/src/components/LayoutComponents/svgs/container.tsx rename to docs-ui/src/components/LayoutComponents/svgs/container.tsx diff --git a/canon-docs/src/components/LayoutComponents/svgs/flex.tsx b/docs-ui/src/components/LayoutComponents/svgs/flex.tsx similarity index 100% rename from canon-docs/src/components/LayoutComponents/svgs/flex.tsx rename to docs-ui/src/components/LayoutComponents/svgs/flex.tsx diff --git a/canon-docs/src/components/LayoutComponents/svgs/grid.tsx b/docs-ui/src/components/LayoutComponents/svgs/grid.tsx similarity index 100% rename from canon-docs/src/components/LayoutComponents/svgs/grid.tsx rename to docs-ui/src/components/LayoutComponents/svgs/grid.tsx diff --git a/docs-ui/src/components/PageTitle/PageTitle.module.css b/docs-ui/src/components/PageTitle/PageTitle.module.css new file mode 100644 index 0000000000..f03b53db96 --- /dev/null +++ b/docs-ui/src/components/PageTitle/PageTitle.module.css @@ -0,0 +1,12 @@ +.container { + margin-bottom: 40px; +} + +.component { + font-size: 11px; + text-transform: uppercase; + font-weight: 500; + letter-spacing: 0.05em; + color: var(--secondary); + margin-bottom: 6px; +} diff --git a/docs-ui/src/components/PageTitle/index.tsx b/docs-ui/src/components/PageTitle/index.tsx new file mode 100644 index 0000000000..540e19eb36 --- /dev/null +++ b/docs-ui/src/components/PageTitle/index.tsx @@ -0,0 +1,23 @@ +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import styles from './PageTitle.module.css'; + +export const PageTitle = ({ + title, + description, + type = 'component', +}: { + title: string; + type?: string; + description: string; +}) => { + return ( +
+
{type}
+ +
+ ); +}; diff --git a/canon-docs/src/components/PropsTable/PropsTable.tsx b/docs-ui/src/components/PropsTable/PropsTable.tsx similarity index 98% rename from canon-docs/src/components/PropsTable/PropsTable.tsx rename to docs-ui/src/components/PropsTable/PropsTable.tsx index a017dc557c..8fedeb7c0c 100644 --- a/canon-docs/src/components/PropsTable/PropsTable.tsx +++ b/docs-ui/src/components/PropsTable/PropsTable.tsx @@ -2,7 +2,7 @@ import * as Table from '../Table'; import { Chip } from '../Chip'; -import { icons } from '../../../../packages/canon'; +import { icons } from '../../../../packages/ui'; // Define a more specific type for the data object type PropData = { diff --git a/canon-docs/src/components/PropsTable/index.ts b/docs-ui/src/components/PropsTable/index.ts similarity index 100% rename from canon-docs/src/components/PropsTable/index.ts rename to docs-ui/src/components/PropsTable/index.ts diff --git a/canon-docs/src/components/Roadmap/Roadmap.tsx b/docs-ui/src/components/Roadmap/Roadmap.tsx similarity index 100% rename from canon-docs/src/components/Roadmap/Roadmap.tsx rename to docs-ui/src/components/Roadmap/Roadmap.tsx diff --git a/canon-docs/src/components/Roadmap/index.ts b/docs-ui/src/components/Roadmap/index.ts similarity index 100% rename from canon-docs/src/components/Roadmap/index.ts rename to docs-ui/src/components/Roadmap/index.ts diff --git a/canon-docs/src/components/Roadmap/list.ts b/docs-ui/src/components/Roadmap/list.ts similarity index 100% rename from canon-docs/src/components/Roadmap/list.ts rename to docs-ui/src/components/Roadmap/list.ts diff --git a/canon-docs/src/components/Roadmap/styles.css b/docs-ui/src/components/Roadmap/styles.css similarity index 100% rename from canon-docs/src/components/Roadmap/styles.css rename to docs-ui/src/components/Roadmap/styles.css diff --git a/canon-docs/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css similarity index 66% rename from canon-docs/src/components/Sidebar/Sidebar.module.css rename to docs-ui/src/components/Sidebar/Sidebar.module.css index 4eb49682df..2b88945c47 100644 --- a/canon-docs/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -6,100 +6,46 @@ .sidebar { display: block; position: fixed; - top: 16px; - left: 16px; - border-radius: 8px; - width: 300px; - height: calc(100vh - 32px); - box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025); + top: 112px; + left: 0; + width: 332px; + height: calc(100vh - 112px); color: var(--primary); - background-color: var(--panel); - border: 1px solid var(--border); - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; overflow: hidden; } } +.version { + font-size: 0.875rem; + font-weight: 500; + color: var(--secondary); + margin-inline: 32px; + border-bottom: 1px solid var(--border); + padding-bottom: 12px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.versionLinks { + display: flex; + align-items: center; + gap: 8px; + + a { + color: var(--secondary); + transition: color 0.2s ease-in-out; + + &:hover { + color: var(--primary); + } + } +} + .root { height: 100%; } -.viewport { - overflow: scroll; - height: 100%; -} - -.content { - padding: 0 20px 20px; -} - -.logoContainer { - padding-left: 6px; - padding-top: 32px; -} - -.logo path { - fill: var(--primary); -} - -.menu { - display: flex; - flex-direction: row; - position: relative; -} - -.section { - width: 100%; - display: flex; - flex-direction: column; - gap: 2px; -} - -.sectionTitle { - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-bold); - padding: 12px 0; - color: var(--primary); - margin-top: 24px; -} - -.line { - text-decoration: none; - align-items: center; - width: 100%; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - height: 26px; - padding: 0 12px; - border-radius: 4px; - transition: background-color 0.2s ease-in-out; - - &:hover { - background-color: var(--surface-1); - } -} - -.line.active { - background-color: var(--surface-1); -} - -.line.active .lineTitle { - color: var(--primary); -} - -.lineTitle { - font-size: 14px; - font-weight: 400; - color: var(--secondary); -} - -.lineStatus { - font-size: 14px; - color: var(--secondary); -} - .scrollbar { display: flex; justify-content: center; @@ -111,7 +57,6 @@ transition: opacity 150ms 300ms; right: -20px; - &[data-hovering], &[data-scrolling] { opacity: 1; transition-duration: 75ms; @@ -131,3 +76,70 @@ border-radius: inherit; background-color: rgba(0, 0, 0, 0.2); } + +.viewport { + overflow: scroll; + height: 100%; +} + +.content { + padding: 0 20px 64px; +} + +.menu { + display: flex; + flex-direction: row; + position: relative; +} + +.section { + width: 100%; + display: flex; + flex-direction: column; + gap: 2px; +} + +.sectionTitle { + font-size: 0.6875rem; + font-weight: 500; + padding: 0 12px 4px; + color: var(--secondary); + margin-top: 40px; + text-transform: uppercase; +} + +.line { + text-decoration: none; + align-items: center; + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 26px; + padding: 0 12px; + border-radius: 4px; + + &:hover { + background-color: var(--action); + } +} + +.line.active { + background-color: var(--action); +} + +.line.active .lineTitle { + color: var(--primary); +} + +.lineTitle { + font-size: 14px; + font-weight: 400; + color: var(--primary); +} + +.lineStatus { + font-size: 14px; + color: var(--secondary); +} diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx new file mode 100644 index 0000000000..4d86398ef7 --- /dev/null +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -0,0 +1,118 @@ +'use client'; + +import styles from './Sidebar.module.css'; +import { components, overview, layoutComponents, theme } from '@/utils/data'; +import { ScrollArea } from '@base-ui-components/react/scroll-area'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { motion } from 'motion/react'; +import { Fragment } from 'react'; +import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; + +const data = [ + { + title: 'Overview', + content: overview, + url: '', + }, + { + title: 'Theme', + content: theme, + url: '/theme', + }, + { + title: 'Layout Components', + content: layoutComponents, + url: '/components', + }, + { + title: 'Components', + content: components, + url: '/components', + }, +]; + +interface SidebarProps { + version: string; +} + +export const Sidebar = ({ version }: SidebarProps) => { + const pathname = usePathname(); + const isPlayground = pathname.includes('/playground'); + + return ( +
+ + + +
+
+ + {data.map(section => { + return ( + +
{section.title}
+ + {section.content.map(item => { + const isActive = + pathname === `${section.url}/${item.slug}`; + + return ( + +
{item.title}
+
+ {item.status === 'alpha' && 'Alpha'} + {item.status === 'beta' && 'Beta'} + {item.status === 'inProgress' && 'In Progress'} + {item.status === 'stable' && 'Stable'} + {item.status === 'deprecated' && 'Deprecated'} +
+ + ); + })} +
+ ); + })} +
+
+
+
+ + + +
+
+ ); +}; diff --git a/canon-docs/src/components/Snippet/client.tsx b/docs-ui/src/components/Snippet/client.tsx similarity index 100% rename from canon-docs/src/components/Snippet/client.tsx rename to docs-ui/src/components/Snippet/client.tsx diff --git a/canon-docs/src/components/Snippet/index.tsx b/docs-ui/src/components/Snippet/index.tsx similarity index 100% rename from canon-docs/src/components/Snippet/index.tsx rename to docs-ui/src/components/Snippet/index.tsx diff --git a/canon-docs/src/components/Snippet/styles.module.css b/docs-ui/src/components/Snippet/styles.module.css similarity index 96% rename from canon-docs/src/components/Snippet/styles.module.css rename to docs-ui/src/components/Snippet/styles.module.css index 41dc9ed684..7371b29c40 100644 --- a/canon-docs/src/components/Snippet/styles.module.css +++ b/docs-ui/src/components/Snippet/styles.module.css @@ -8,7 +8,6 @@ border-radius: 4px; box-shadow: inset 0 0 0 1px var(--border); background-color: var(--bg); - transition: all 0.2s ease-in-out; padding: 1px; position: relative; } diff --git a/canon-docs/src/components/Table/Table.tsx b/docs-ui/src/components/Table/Table.tsx similarity index 100% rename from canon-docs/src/components/Table/Table.tsx rename to docs-ui/src/components/Table/Table.tsx diff --git a/canon-docs/src/components/Table/index.ts b/docs-ui/src/components/Table/index.ts similarity index 100% rename from canon-docs/src/components/Table/index.ts rename to docs-ui/src/components/Table/index.ts diff --git a/canon-docs/src/components/Table/styles.module.css b/docs-ui/src/components/Table/styles.module.css similarity index 94% rename from canon-docs/src/components/Table/styles.module.css rename to docs-ui/src/components/Table/styles.module.css index 3381f39e58..5a5ebab450 100644 --- a/canon-docs/src/components/Table/styles.module.css +++ b/docs-ui/src/components/Table/styles.module.css @@ -19,7 +19,6 @@ text-align: left; background-color: var(--panel) !important; font-size: 16px; - transition: background-color 0.2s ease-in-out; & p { margin: 0 !important; diff --git a/canon-docs/src/components/Tabs/index.tsx b/docs-ui/src/components/Tabs/index.tsx similarity index 100% rename from canon-docs/src/components/Tabs/index.tsx rename to docs-ui/src/components/Tabs/index.tsx diff --git a/canon-docs/src/components/Tabs/parts.tsx b/docs-ui/src/components/Tabs/parts.tsx similarity index 77% rename from canon-docs/src/components/Tabs/parts.tsx rename to docs-ui/src/components/Tabs/parts.tsx index 3d02683cef..2a394d248b 100644 --- a/canon-docs/src/components/Tabs/parts.tsx +++ b/docs-ui/src/components/Tabs/parts.tsx @@ -1,7 +1,6 @@ 'use client'; import { Tabs as TabsPrimitive } from '@base-ui-components/react/tabs'; -import { Text } from '../../../../packages/canon'; import styles from './styles.module.css'; export const Root = ({ @@ -27,14 +26,8 @@ export const Tab = (props: React.ComponentProps) => ( {...props} render={({ children, ...rest }, state) => { return ( - ); }} diff --git a/docs-ui/src/components/Tabs/styles.module.css b/docs-ui/src/components/Tabs/styles.module.css new file mode 100644 index 0000000000..8fdffc3f4b --- /dev/null +++ b/docs-ui/src/components/Tabs/styles.module.css @@ -0,0 +1,41 @@ +.root { + margin-top: 40px; +} + +.list { + display: flex; + gap: 24px; + border-bottom: 1px solid var(--border); + position: relative; + margin-bottom: 24px; +} + +.tab { + all: unset; + cursor: pointer; + padding-bottom: 12px; + font-size: 14px; + font-weight: 600; + color: var(--primary); + + &[data-selected='false'] { + color: var(--secondary); + } + + &[data-selected='false']:hover { + color: var(--primary); + transition: color 0.2s ease-in-out; + } +} + +.indicator { + position: absolute; + bottom: -1px; + left: var(--active-tab-left); + width: var(--active-tab-width); + height: 1px; + background-color: var(--primary); + transition-property: left, width; + transition-duration: 200ms; + transition-timing-function: ease-in-out; +} diff --git a/docs-ui/src/components/Theming/index.tsx b/docs-ui/src/components/Theming/index.tsx new file mode 100644 index 0000000000..fb669253a2 --- /dev/null +++ b/docs-ui/src/components/Theming/index.tsx @@ -0,0 +1,52 @@ +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import { Component } from '@/utils/changelog'; +import { componentDefinitions } from '../../../../packages/ui/src/utils/componentDefinitions'; +import type { DataAttributeValues } from '../../../../packages/ui/src/types'; + +export function Theming({ component }: { component: Component }) { + const componentDefinition = componentDefinitions[component]; + + if (!componentDefinition) { + return null; + } + + const classNames = componentDefinition.classNames; + const dataAttributes = componentDefinition.dataAttributes; + + // Get the first class name + const firstClassName = Object.values(classNames)[0]; + + // Create array of selectors combining first class name with data attributes + const selectorArray: string[] = []; + + if (dataAttributes) { + Object.entries(dataAttributes).forEach( + ([attributeName, attributeValues]) => { + (attributeValues as DataAttributeValues).forEach(value => { + selectorArray.push( + `${firstClassName}[data-${attributeName}="${value}"]`, + ); + }); + }, + ); + } + + const classNamesArray = [ + `${firstClassName}`, + ...selectorArray, + ...Object.values(classNames).slice(1), + ]; + + return ( + `- \`${selector}\``).join('\n')} + `} + /> + ); +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css new file mode 100644 index 0000000000..8142c5464e --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -0,0 +1,44 @@ +.toolbar { + position: fixed; + display: flex; + top: 0; + left: 32px; + right: 32px; + height: 112px; + z-index: 10; + align-items: center; + justify-content: space-between; + padding-left: 0.25rem; +} + +@media (min-width: 960px) { + .toolbar { + left: 332px; + right: 40px; + } +} + +.left { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.name { + margin-top: 3px; + font-size: 28px; + color: #26c9ad; + font-weight: 500; +} + +.actions { + display: none; +} + +@media (min-width: 600px) { + .actions { + display: flex; + align-items: center; + gap: 1rem; + } +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 0000000000..952b48f5ac --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { ThemeSelector } from './theme'; +import { ThemeNameSelector } from './theme-name'; +import styles from './Toolbar.module.css'; + +export const Toolbar = () => { + return ( +
+
+ + + +
UI
+
+
+ + +
+
+ ); +}; diff --git a/docs-ui/src/components/Toolbar/index.ts b/docs-ui/src/components/Toolbar/index.ts new file mode 100644 index 0000000000..f362defa5e --- /dev/null +++ b/docs-ui/src/components/Toolbar/index.ts @@ -0,0 +1 @@ +export { Toolbar } from './Toolbar'; diff --git a/canon-docs/src/components/Toolbar/theme-name.module.css b/docs-ui/src/components/Toolbar/theme-name.module.css similarity index 87% rename from canon-docs/src/components/Toolbar/theme-name.module.css rename to docs-ui/src/components/Toolbar/theme-name.module.css index 87d6538e81..58471b8fd7 100644 --- a/canon-docs/src/components/Toolbar/theme-name.module.css +++ b/docs-ui/src/components/Toolbar/theme-name.module.css @@ -4,21 +4,20 @@ align-items: center; justify-content: space-between; gap: 0.75rem; - height: 2rem; - padding-left: 0.875rem; - padding-right: 0.75rem; + height: 3rem; + padding-left: 1.25rem; + padding-right: 1rem; margin: 0; outline: 0; border: 1px solid var(--color-gray-200); - border-radius: 0.375rem; + border-radius: 3rem; font-family: inherit; font-size: 1rem; line-height: 1.5rem; color: var(--color-gray-900); cursor: pointer; user-select: none; - background-color: var(--surface-1); - transition: background-color 0.2s ease-in-out; + background-color: var(--action); &:focus-visible { outline: 2px solid var(--color-blue); @@ -31,8 +30,8 @@ } .SelectValue { - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-regular); + font-size: 0.875rem; + font-weight: 400; } .Positioner { @@ -82,8 +81,8 @@ padding-block: 0.5rem; padding-left: 0.625rem; padding-right: 1rem; - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-bold); + font-size: 0.875rem; + font-weight: 600; display: grid; gap: 0.5rem; align-items: center; diff --git a/canon-docs/src/components/Toolbar/theme-name.tsx b/docs-ui/src/components/Toolbar/theme-name.tsx similarity index 95% rename from canon-docs/src/components/Toolbar/theme-name.tsx rename to docs-ui/src/components/Toolbar/theme-name.tsx index 277ecad9df..3cf0d088ef 100644 --- a/canon-docs/src/components/Toolbar/theme-name.tsx +++ b/docs-ui/src/components/Toolbar/theme-name.tsx @@ -2,11 +2,12 @@ import { Select } from '@base-ui-components/react/select'; import styles from './theme-name.module.css'; -import { Icon } from '@backstage/canon'; +import { Icon } from '@backstage/ui'; import { usePlayground } from '@/utils/playground-context'; const themes = [ { name: 'Backstage', value: 'default' }, + { name: 'Spotify', value: 'spotify' }, { name: 'Custom theme', value: 'custom' }, ]; diff --git a/canon-docs/src/components/Toolbar/theme.module.css b/docs-ui/src/components/Toolbar/theme.module.css similarity index 70% rename from canon-docs/src/components/Toolbar/theme.module.css rename to docs-ui/src/components/Toolbar/theme.module.css index 641909ac1e..c5490a72d7 100644 --- a/canon-docs/src/components/Toolbar/theme.module.css +++ b/docs-ui/src/components/Toolbar/theme.module.css @@ -1,22 +1,17 @@ .tabs { border-radius: 0.375rem; width: 100%; - background-color: var(--surface-1); - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; } .tabsTheme { width: 100px; border-radius: 0.375rem; - background-color: var(--surface-1); - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; } .list { display: flex; position: relative; z-index: 0; - padding-inline: 0.25rem; gap: 0.25rem; } @@ -31,9 +26,10 @@ appearance: none; color: var(--secondary); user-select: none; - height: 2rem; flex: 1; cursor: pointer; + width: 3rem; + height: 3rem; &[data-selected] { color: var(--primary); @@ -57,7 +53,7 @@ position: absolute; inset: 0.25rem 0; border-radius: 0.25rem; - outline: 2px solid var(--panel); + outline: 2px solid var(--action); outline-offset: -1px; } } @@ -74,10 +70,10 @@ top: 50%; translate: var(--active-tab-left) -50%; width: var(--active-tab-width); - height: 1.5rem; - border-radius: 0.25rem; - background-color: var(--panel); - transition-property: translate, width, background-color; + height: 3rem; + border-radius: 3rem; + background-color: var(--action); + transition-property: translate, width; transition-duration: 200ms; transition-timing-function: ease-in-out; } diff --git a/canon-docs/src/components/Toolbar/theme.tsx b/docs-ui/src/components/Toolbar/theme.tsx similarity index 94% rename from canon-docs/src/components/Toolbar/theme.tsx rename to docs-ui/src/components/Toolbar/theme.tsx index 94224048ea..ef3d842056 100644 --- a/canon-docs/src/components/Toolbar/theme.tsx +++ b/docs-ui/src/components/Toolbar/theme.tsx @@ -1,7 +1,7 @@ 'use client'; import { Tabs } from '@base-ui-components/react/tabs'; -import { Icon } from '@backstage/canon'; +import { Icon } from '@backstage/ui'; import { usePlayground } from '@/utils/playground-context'; import styles from './theme.module.css'; diff --git a/canon-docs/src/content/components/avatar.mdx b/docs-ui/src/content/components/avatar.mdx similarity index 70% rename from canon-docs/src/content/components/avatar.mdx rename to docs-ui/src/content/components/avatar.mdx index 418d19dcd4..be1fb070d1 100644 --- a/canon-docs/src/content/components/avatar.mdx +++ b/docs-ui/src/content/components/avatar.mdx @@ -8,11 +8,14 @@ import { snippetSizes, snippetFallback, } from './avatar.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Avatar - -An avatar component with a fallback for initials. + `} /> - +## Usage + + ## API reference @@ -63,3 +57,7 @@ If the image is not available, the avatar will show the initials of the name. preview={} code={snippetFallback} /> + + + + diff --git a/canon-docs/src/content/components/avatar.props.ts b/docs-ui/src/content/components/avatar.props.ts similarity index 99% rename from canon-docs/src/content/components/avatar.props.ts rename to docs-ui/src/content/components/avatar.props.ts index ddcf852cb9..8cc53eeff3 100644 --- a/canon-docs/src/content/components/avatar.props.ts +++ b/docs-ui/src/content/components/avatar.props.ts @@ -18,7 +18,7 @@ export const avatarPropDefs: Record = { ...stylePropDefs, }; -export const snippetUsage = `import { Avatar } from '@backstage/canon'; +export const snippetUsage = `import { Avatar } from '@backstage/ui'; - +## Usage + + ## API reference @@ -53,3 +59,7 @@ A simple example of how to use the Box component. Here's a view when buttons are responsive. + + + + diff --git a/canon-docs/src/content/components/box.props.ts b/docs-ui/src/content/components/box.props.ts similarity index 91% rename from canon-docs/src/content/components/box.props.ts rename to docs-ui/src/content/components/box.props.ts index e541a6059f..0ee45c80f4 100644 --- a/canon-docs/src/content/components/box.props.ts +++ b/docs-ui/src/content/components/box.props.ts @@ -23,7 +23,7 @@ export const boxPropDefs: Record = { ...stylePropDefs, }; -export const snippetUsage = `import { Box } from '@backstage/canon'; +export const snippetUsage = `import { Box } from '@backstage/ui'; `; diff --git a/canon-docs/src/content/components/button-icon.mdx b/docs-ui/src/content/components/button-icon.mdx similarity index 76% rename from canon-docs/src/content/components/button-icon.mdx rename to docs-ui/src/content/components/button-icon.mdx index b020b19f33..e1f27e0601 100644 --- a/canon-docs/src/content/components/button-icon.mdx +++ b/docs-ui/src/content/components/button-icon.mdx @@ -12,11 +12,14 @@ import { buttonIconResponsiveSnippet, buttonIconAsLinkSnippet, } from './button-icon.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# ButtonIcon - -A button component with a single icon that can be used to trigger actions. + - +## Usage + + ## API reference @@ -78,3 +79,7 @@ Here's a view when buttons are disabled. Here's a view when buttons are responsive. + + + + diff --git a/canon-docs/src/content/components/button-icon.props.ts b/docs-ui/src/content/components/button-icon.props.ts similarity index 94% rename from canon-docs/src/content/components/button-icon.props.ts rename to docs-ui/src/content/components/button-icon.props.ts index a21bf3cd57..2ba7372a9c 100644 --- a/canon-docs/src/content/components/button-icon.props.ts +++ b/docs-ui/src/content/components/button-icon.props.ts @@ -29,7 +29,7 @@ export const buttonIconPropDefs: Record = { ...stylePropDefs, }; -export const buttonIconUsageSnippet = `import { ButtonIcon } from '@backstage/canon'; +export const buttonIconUsageSnippet = `import { ButtonIcon } from '@backstage/ui'; `; @@ -52,8 +52,8 @@ export const buttonIconDisabledSnippet = `} variant={{ initial: 'primary', lg: 'secondary' }} />`; -export const buttonIconAsLinkSnippet = `import { ButtonLink } from '@backstage/canon'; +export const buttonIconAsLinkSnippet = `import { ButtonLink } from '@backstage/ui'; - + Button `; diff --git a/canon-docs/src/content/components/button-link.mdx b/docs-ui/src/content/components/button-link.mdx similarity index 79% rename from canon-docs/src/content/components/button-link.mdx rename to docs-ui/src/content/components/button-link.mdx index f6da987941..5ce538838d 100644 --- a/canon-docs/src/content/components/button-link.mdx +++ b/docs-ui/src/content/components/button-link.mdx @@ -11,11 +11,14 @@ import { buttonLinkDisabledSnippet, buttonLinkResponsiveSnippet, } from './button-link.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# ButtonLink - -A button component that can be used as a link. + - +## Usage + + ## API reference @@ -89,3 +90,7 @@ Here's a view when buttons are disabled. Here's a view when buttons are responsive. + + + + diff --git a/canon-docs/src/content/components/button-link.props.ts b/docs-ui/src/content/components/button-link.props.ts similarity index 99% rename from canon-docs/src/content/components/button-link.props.ts rename to docs-ui/src/content/components/button-link.props.ts index b92b3154e5..758d6fd811 100644 --- a/canon-docs/src/content/components/button-link.props.ts +++ b/docs-ui/src/content/components/button-link.props.ts @@ -31,7 +31,7 @@ export const buttonLinkPropDefs: Record = { ...stylePropDefs, }; -export const buttonLinkSnippetUsage = `import { ButtonLink } from '@backstage/canon'; +export const buttonLinkSnippetUsage = `import { ButtonLink } from '@backstage/ui'; `; diff --git a/canon-docs/src/content/components/button.mdx b/docs-ui/src/content/components/button.mdx similarity index 81% rename from canon-docs/src/content/components/button.mdx rename to docs-ui/src/content/components/button.mdx index c0053d0f5e..a25115012b 100644 --- a/canon-docs/src/content/components/button.mdx +++ b/docs-ui/src/content/components/button.mdx @@ -12,11 +12,14 @@ import { buttonResponsiveSnippet, buttonAsLinkSnippet, } from './button.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; -# Button - -A button component that can be used to trigger actions. + - +## Usage + + ## API reference @@ -102,3 +103,7 @@ If you want to use a button as a link, please use the `ButtonLink` component. preview={} code={buttonAsLinkSnippet} /> + + + + diff --git a/canon-docs/src/content/components/button.props.ts b/docs-ui/src/content/components/button.props.ts similarity index 95% rename from canon-docs/src/content/components/button.props.ts rename to docs-ui/src/content/components/button.props.ts index b32cba4725..4647c20956 100644 --- a/canon-docs/src/content/components/button.props.ts +++ b/docs-ui/src/content/components/button.props.ts @@ -28,7 +28,7 @@ export const buttonPropDefs: Record = { ...stylePropDefs, }; -export const buttonSnippetUsage = `import { Button } from '@backstage/canon'; +export const buttonSnippetUsage = `import { Button } from '@backstage/ui'; , + menuItems, + }, + decorators: [withRouter], +}; + +export const WithBreadcrumbs: Story = { + args: { + breadcrumbs, + }, + decorators: [withRouter], +}; + +export const WithAllComponents: Story = { + args: { + menuItems, + tabs, + breadcrumbs, + }, + decorators: [withRouter], +}; + +export const WithLayout: Story = { + args: { + menuItems, + breadcrumbs, + }, + decorators: layoutDecorator, + render: args => ( + <> +
+ Custom action} + /> + + ), +}; + +export const WithLayoutNoTabs: Story = { + args: { + menuItems, + breadcrumbs, + }, + decorators: layoutDecorator, + render: args => ( + <> +
+ + + ), +}; + +export const WithEverything: Story = { + args: { + menuItems, + breadcrumbs, + tabs, + titleLink: '/', + }, + decorators: layoutDecorator, + render: args => ( + <> +
+ } /> + } /> + } /> + + } + /> + + + + + } + /> + + ), +}; + +export const WithMockedURLCampaigns: Story = { + args: { + tabs, + }, + render: args => ( + +
+ + + Current URL is mocked to be: /campaigns + + + Notice how the "Campaigns" tab is selected (highlighted) because it + matches the current path. + + + + ), +}; + +export const WithMockedURLIntegrations: Story = { + args: { + tabs, + }, + render: args => ( + +
+ + + Current URL is mocked to be: /integrations + + + Notice how the "Integrations" tab is selected (highlighted) because it + matches the current path. + + + + ), +}; + +export const WithMockedURLNoMatch: Story = { + args: { + tabs, + }, + render: args => ( + +
+ + + Current URL is mocked to be: /some-other-page + + + No tab is selected because the current path doesn't match any tab's + href. + + + Tabs without href (like "Overview", "Checks", "Tracks") fall back to + React Aria's internal state. + + + + ), +}; + +export const WithTabsMatchingStrategies: Story = { + args: { + title: 'Route Matching Demo', + tabs: [ + { + id: 'home', + label: 'Home', + href: '/home', + }, + { + id: 'mentorship', + label: 'Mentorship', + href: '/mentorship', + matchStrategy: 'prefix', + }, + { + id: 'catalog', + label: 'Catalog', + href: '/catalog', + matchStrategy: 'prefix', + }, + { + id: 'settings', + label: 'Settings', + href: '/settings', + }, + ], + }, + render: args => ( + +
+ + + Current URL: /mentorship/events + +
+ + Notice how the "Mentorship" tab is active even though we're on a + nested route. This is because it uses{' '} + matchStrategy="prefix". + +
+ + • Home: exact matching (default) - not active + + + • Mentorship: prefix matching - IS active (URL starts + with /mentorship) + + + • Catalog: prefix matching - not active + + + • Settings: exact matching (default) - not active + +
+ + ), +}; + +export const WithTabsExactMatching: Story = { + args: { + title: 'Exact Matching Demo', + tabs: [ + { + id: 'mentorship', + label: 'Mentorship', + href: '/mentorship', + }, + { + id: 'events', + label: 'Events', + href: '/mentorship/events', + }, + { + id: 'mentors', + label: 'Mentors', + href: '/mentorship/mentors', + }, + ], + }, + render: args => ( + +
+ + + Current URL: /mentorship/events + +
+ + With default exact matching, only the "Events" tab is active because + it exactly matches the current URL. The "Mentorship" tab is not active + even though the URL is under /mentorship. + +
+ + ), +}; + +export const WithTabsPrefixMatchingDeep: Story = { + args: { + title: 'Deep Nesting Demo', + tabs: [ + { + id: 'catalog', + label: 'Catalog', + href: '/catalog', + matchStrategy: 'prefix', + }, + { + id: 'users', + label: 'Users', + href: '/catalog/users', + matchStrategy: 'prefix', + }, + { + id: 'components', + label: 'Components', + href: '/catalog/components', + matchStrategy: 'prefix', + }, + ], + }, + render: args => ( + +
+ + + Current URL: /catalog/users/john/details + +
+ Both "Catalog" and "Users" tabs are active because: + + • Catalog: URL starts with /catalog + + + • Users: URL starts with /catalog/users + + + • Components: not active (URL doesn't start with + /catalog/components) + +
+ + This demonstrates how prefix matching works with deeply nested routes. + +
+ + ), +}; diff --git a/packages/ui/src/components/Header/Header.styles.css b/packages/ui/src/components/Header/Header.styles.css new file mode 100644 index 0000000000..b978033561 --- /dev/null +++ b/packages/ui/src/components/Header/Header.styles.css @@ -0,0 +1,129 @@ +/* + * Copyright 2024 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. + */ + +.bui-HeaderToolbar { + position: sticky; + top: 0; + z-index: 10; + margin-bottom: var(--bui-space-6); + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0px; + right: 0px; + height: 16px; + background-color: var(--bui-bg); + z-index: 0; + } + + &[data-has-tabs='true'] { + margin-bottom: 0; + } +} + +.bui-HeaderToolbarWrapper { + position: relative; + z-index: 1; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + background-color: var(--bui-bg-surface-1); + padding-inline: var(--bui-space-5); + border-bottom: 1px solid var(--bui-border); + color: var(--bui-fg-primary); + height: 52px; +} + +.bui-HeaderToolbarContent { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); +} + +.bui-HeaderToolbarName { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); + font-size: var(--bui-font-size-3); + font-weight: var(--bui-font-weight-regular); + flex-shrink: 0; +} + +.bui-HeaderToolbarIcon { + width: 16px; + height: 16px; + color: var(--bui-fg-primary); + + & svg { + width: 100%; + height: 100%; + } +} + +.bui-HeaderToolbarControls { + position: absolute; + right: var(--bui-space-5); + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); +} + +.bui-HeaderBreadcrumbs { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); + font-size: var(--bui-font-size-3); + font-weight: var(--bui-font-weight-regular); +} + +.bui-HeaderBreadcrumb { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); +} + +.bui-HeaderBreadcrumbLink { + color: var(--bui-fg-secondary); + text-decoration: none; + cursor: pointer; + + &[data-active='true'] { + color: var(--bui-fg-primary); + } +} + +.bui-HeaderBreadcrumbSeparator { + width: 16px; + height: 16px; + color: var(--bui-fg-secondary); +} + +.bui-HeaderTabsWrapper { + margin-bottom: var(--bui-space-4); + padding-inline: var(--bui-space-3); + border-bottom: 1px solid var(--bui-border); + background-color: var(--bui-bg-surface-1); +} diff --git a/packages/ui/src/components/Header/Header.tsx b/packages/ui/src/components/Header/Header.tsx new file mode 100644 index 0000000000..745a524e57 --- /dev/null +++ b/packages/ui/src/components/Header/Header.tsx @@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { HeaderProps } from './types'; +import { HeaderToolbar } from './HeaderToolbar'; +import { Tabs, TabList, Tab } from '../Tabs'; +import { useStyles } from '../../hooks/useStyles'; +import { type NavigateOptions } from 'react-router-dom'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions; + } +} + +/** + * A component that renders a toolbar. + * + * @public + */ +export const Header = (props: HeaderProps) => { + const { + tabs, + icon, + title, + titleLink, + menuItems, + breadcrumbs, + customActions, + onTabSelectionChange, + } = props; + + const { classNames } = useStyles('Header'); + + const hasTabs = tabs && tabs.length > 0; + + return ( + <> + + {tabs && ( +
+ + + {tabs?.map(tab => ( + + {tab.label} + + ))} + + +
+ )} + + ); +}; diff --git a/packages/ui/src/components/Header/HeaderToolbar.tsx b/packages/ui/src/components/Header/HeaderToolbar.tsx new file mode 100644 index 0000000000..cc165dc661 --- /dev/null +++ b/packages/ui/src/components/Header/HeaderToolbar.tsx @@ -0,0 +1,185 @@ +/* + * Copyright 2024 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 { Link, RouterProvider } from 'react-aria-components'; +import { useStyles } from '../../hooks/useStyles'; +import { useRef, useState, useEffect } from 'react'; +import { RiArrowRightSLine, RiMore2Line, RiShapesLine } from '@remixicon/react'; +import type { HeaderToolbarProps } from './types'; +import { ButtonIcon } from '../ButtonIcon'; +import { Menu } from '../Menu'; +import { Text } from '../Text'; +import { motion, useScroll, useTransform } from 'motion/react'; +import { useNavigate, useHref } from 'react-router-dom'; + +/** + * A component that renders a toolbar. + * + * @internal + */ +export const HeaderToolbar = (props: HeaderToolbarProps) => { + const { + icon, + title, + titleLink, + menuItems, + breadcrumbs, + customActions, + hasTabs, + } = props; + const { classNames } = useStyles('Header'); + let navigate = useNavigate(); + const { scrollY } = useScroll(); + const breadcrumbOpacity = useTransform(scrollY, [80, 120], [0, 1]); + + // Refs for collision detection + const toolbarWrapperRef = useRef(null); + const toolbarContentRef = useRef(null); + const toolbarControlsRef = useRef(null); + + // State for breadcrumb visibility + const [showBreadcrumbs, setShowBreadcrumbs] = useState(true); + + // Set up resize observer + useEffect(() => { + const wrapper = toolbarWrapperRef.current; + if (!wrapper) return; + + const resizeObserver = new ResizeObserver(() => { + const wrapper = toolbarWrapperRef.current; + const content = toolbarContentRef.current; + const options = toolbarControlsRef.current; + + if (!wrapper || !content) return; + + // Get dimensions + const wrapperRect = wrapper.getBoundingClientRect(); + const wrapperWidth = wrapperRect.width; + const wrapperPadding = 24; // 12px on each side (var(--bui-space-3)) + const availableWidth = wrapperWidth - wrapperPadding; + + // Calculate required width for content + const contentRect = content.getBoundingClientRect(); + const contentWidth = contentRect?.width || 0; + + // Calculate options width (if exists) + const optionsRect = options?.getBoundingClientRect(); + const optionsWidth = optionsRect?.width || 0; + + // Check if we need to hide breadcrumbs + const shouldShowBreadcrumbs = + contentWidth + optionsWidth + 32 <= availableWidth; + + // Only update state if the value actually changed to prevent flickering + setShowBreadcrumbs(prev => + prev !== shouldShowBreadcrumbs ? shouldShowBreadcrumbs : prev, + ); + }); + + resizeObserver.observe(wrapper); + + return () => { + resizeObserver.disconnect(); + }; + }, []); + + const titleContent = ( + <> +
{icon || }
+ {title || 'Your plugin'} + + ); + + return ( + +
+
+
+ {titleLink ? ( + + {titleContent} + + ) : ( +
{titleContent}
+ )} + {breadcrumbs && ( + + + {breadcrumbs.map((breadcrumb, index) => ( +
+ + {breadcrumb.label} + + {index < breadcrumbs.length - 1 && ( + + )} +
+ ))} +
+ )} +
+
+ {customActions} + {menuItems && ( + + ( + } + variant="tertiary" + {...props} + /> + )} + /> + + + + {menuItems.map(option => ( + option.onClick?.()} + > + {option.label} + + ))} + + + + + )} +
+
+
+
+ ); +}; diff --git a/packages/ui/src/components/Header/index.tsx b/packages/ui/src/components/Header/index.tsx new file mode 100644 index 0000000000..c90dbb3abb --- /dev/null +++ b/packages/ui/src/components/Header/index.tsx @@ -0,0 +1,23 @@ +/* + * Copyright 2024 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 { Header } from './Header'; +export type { + HeaderProps, + HeaderTab, + HeaderMenuItem, + HeaderBreadcrumb, +} from './types'; diff --git a/packages/ui/src/components/Header/types.ts b/packages/ui/src/components/Header/types.ts new file mode 100644 index 0000000000..53f36a2f01 --- /dev/null +++ b/packages/ui/src/components/Header/types.ts @@ -0,0 +1,87 @@ +/* + * Copyright 2024 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 { TabsProps } from 'react-aria-components'; +import { TabMatchStrategy } from '../Tabs'; + +/** + * Props for the main Header component. + * + * @public + */ +export interface HeaderProps { + icon?: React.ReactNode; + title?: string; + titleLink?: string; + breadcrumbs?: HeaderBreadcrumb[]; + customActions?: React.ReactNode; + menuItems?: HeaderMenuItem[]; + tabs?: HeaderTab[]; + onTabSelectionChange?: TabsProps['onSelectionChange']; +} + +/** + * Represents a tab item in the header navigation. + * + * @public + */ +export interface HeaderTab { + id: string; + label: string; + href?: string; + /** + * Strategy for matching the current route to determine if this tab should be active. + * - 'exact': Tab href must exactly match the current pathname (default) + * - 'prefix': Tab is active if current pathname starts with tab href + */ + matchStrategy?: TabMatchStrategy; +} + +/** + * Represents an option item in the header dropdown menu. + * + * @public + */ +export interface HeaderMenuItem { + label: string; + value: string; + onClick?: () => void; +} + +/** + * Represents a breadcrumb item in the header. + * + * @public + */ +export interface HeaderBreadcrumb { + label: string; + href: string; +} + +/** + * Props for the HeaderToolbar component. + * + * @internal + */ +export interface HeaderToolbarProps { + icon?: HeaderProps['icon']; + title?: HeaderProps['title']; + titleLink?: HeaderProps['titleLink']; + breadcrumbs?: HeaderProps['breadcrumbs']; + customActions?: HeaderProps['customActions']; + menuItems?: HeaderProps['menuItems']; + hasTabs?: boolean; +} diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx new file mode 100644 index 0000000000..b8e7cf89e4 --- /dev/null +++ b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx @@ -0,0 +1,312 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj, StoryFn } from '@storybook/react'; +import { HeaderPage } from './HeaderPage'; +import type { HeaderTab, HeaderMenuItem } from '../Header/types'; +import { MemoryRouter } from 'react-router-dom'; +import { Button } from '../Button'; +import { Container } from '../Container'; +import { Text } from '../Text'; + +const meta = { + title: 'Components/HeaderPage', + component: HeaderPage, + parameters: { + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const tabs: HeaderTab[] = [ + { + id: 'overview', + label: 'Overview', + }, + { + id: 'checks', + label: 'Checks', + }, + { + id: 'tracks', + label: 'Tracks', + }, + { + id: 'campaigns', + label: 'Campaigns', + }, + { + id: 'integrations', + label: 'Integrations', + }, +]; + +const menuItems: HeaderMenuItem[] = [ + { + label: 'Settings', + value: 'settings', + }, + { + label: 'Invite new members', + value: 'invite-new-members', + }, +]; + +const withRouter = (Story: StoryFn) => ( + + + +); + +// Extract layout decorator as a reusable constant +const layoutDecorator = [ + (Story: StoryFn) => ( + <> +
+
+ + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, + quos. + + +
+ + ), +]; + +export const Default: Story = { + args: { + title: 'Header Page', + }, +}; + +export const WithTabs: Story = { + args: { + ...Default.args, + tabs, + }, + decorators: [withRouter], +}; + +export const WithMenuItems: Story = { + args: { + ...Default.args, + menuItems, + }, +}; + +export const WithCustomActions: Story = { + render: () => ( + Custom action} + /> + ), +}; + +export const WithEverything: Story = { + decorators: [withRouter], + render: () => ( + Custom action} + /> + ), +}; + +export const WithLayout: Story = { + args: { + ...WithEverything.args, + }, + decorators: [withRouter, ...layoutDecorator], + render: WithEverything.render, +}; + +export const WithTabsMatchingStrategies: Story = { + args: { + title: 'Route Matching Demo', + tabs: [ + { + id: 'home', + label: 'Home', + href: '/home', + }, + { + id: 'mentorship', + label: 'Mentorship', + href: '/mentorship', + matchStrategy: 'prefix', + }, + { + id: 'catalog', + label: 'Catalog', + href: '/catalog', + matchStrategy: 'prefix', + }, + { + id: 'settings', + label: 'Settings', + href: '/settings', + }, + ], + }, + render: args => ( + + + + + Current URL: /mentorship/events + +
+ + Notice how the "Mentorship" tab is active even though we're on a + nested route. This is because it uses{' '} + matchStrategy="prefix". + +
+ + • Home: exact matching (default) - not active + + + • Mentorship: prefix matching - IS active (URL starts + with /mentorship) + + + • Catalog: prefix matching - not active + + + • Settings: exact matching (default) - not active + +
+
+ ), +}; + +export const WithTabsExactMatching: Story = { + args: { + title: 'Exact Matching Demo', + tabs: [ + { + id: 'mentorship', + label: 'Mentorship', + href: '/mentorship', + }, + { + id: 'events', + label: 'Events', + href: '/mentorship/events', + }, + { + id: 'mentors', + label: 'Mentors', + href: '/mentorship/mentors', + }, + ], + }, + render: args => ( + + + + + Current URL: /mentorship/events + +
+ + With default exact matching, only the "Events" tab is active because + it exactly matches the current URL. The "Mentorship" tab is not active + even though the URL is under /mentorship. + +
+
+ ), +}; + +export const WithTabsPrefixMatchingDeep: Story = { + args: { + title: 'Deep Nesting Demo', + tabs: [ + { + id: 'catalog', + label: 'Catalog', + href: '/catalog', + matchStrategy: 'prefix', + }, + { + id: 'users', + label: 'Users', + href: '/catalog/users', + matchStrategy: 'prefix', + }, + { + id: 'components', + label: 'Components', + href: '/catalog/components', + matchStrategy: 'prefix', + }, + ], + }, + render: args => ( + + + + + Current URL: /catalog/users/john/details + +
+ Both "Catalog" and "Users" tabs are active because: + + • Catalog: URL starts with /catalog + + + • Users: URL starts with /catalog/users + + + • Components: not active (URL doesn't start with + /catalog/components) + +
+ + This demonstrates how prefix matching works with deeply nested routes. + +
+
+ ), +}; diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.styles.css b/packages/ui/src/components/HeaderPage/HeaderPage.styles.css new file mode 100644 index 0000000000..8001ab4f37 --- /dev/null +++ b/packages/ui/src/components/HeaderPage/HeaderPage.styles.css @@ -0,0 +1,41 @@ +/* + * Copyright 2024 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. + */ + +.bui-HeaderPage { + display: flex; + flex-direction: column; + gap: var(--bui-space-1); + padding-inline: var(--bui-space-5); + margin-top: var(--bui-space-6); + margin-bottom: var(--bui-space-6); +} + +.bui-HeaderPageContent { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.bui-HeaderPageTabsWrapper { + margin-left: -8px; +} + +.bui-HeaderPageControls { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--bui-space-2); +} diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.tsx b/packages/ui/src/components/HeaderPage/HeaderPage.tsx new file mode 100644 index 0000000000..5eeab28b2f --- /dev/null +++ b/packages/ui/src/components/HeaderPage/HeaderPage.tsx @@ -0,0 +1,92 @@ +/* + * 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 type { HeaderPageProps } from './types'; +import { Menu } from '../Menu'; +import { Text } from '../Text'; +import { ButtonIcon } from '../ButtonIcon'; +import { RiMore2Line } from '@remixicon/react'; +import { Tabs, TabList, Tab } from '../Tabs'; +import { useStyles } from '../../hooks/useStyles'; + +/** + * A component that renders a header page. + * + * @public + */ +export const HeaderPage = (props: HeaderPageProps) => { + const { title, menuItems, tabs, customActions } = props; + const { classNames } = useStyles('HeaderPage'); + + return ( +
+
+ + {title} + +
+ {customActions} + {menuItems && ( + + ( + } + variant="tertiary" + /> + )} + /> + + + + {menuItems.map(menuItem => ( + menuItem.onClick?.()} + > + {menuItem.label} + + ))} + + + + + )} +
+
+ {tabs && ( +
+ + + {tabs.map(tab => ( + + {tab.label} + + ))} + + +
+ )} +
+ ); +}; diff --git a/packages/ui/src/components/HeaderPage/index.tsx b/packages/ui/src/components/HeaderPage/index.tsx new file mode 100644 index 0000000000..49ec9b51bb --- /dev/null +++ b/packages/ui/src/components/HeaderPage/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright 2024 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 { HeaderPage } from './HeaderPage'; +export type { HeaderPageProps } from './types'; diff --git a/packages/ui/src/components/HeaderPage/types.ts b/packages/ui/src/components/HeaderPage/types.ts new file mode 100644 index 0000000000..0a55a9456a --- /dev/null +++ b/packages/ui/src/components/HeaderPage/types.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { HeaderTab, HeaderMenuItem } from '../Header/types'; + +/** + * Props for the main HeaderPage component. + * + * @public + */ +export interface HeaderPageProps { + title?: string; + customActions?: React.ReactNode; + menuItems?: HeaderMenuItem[]; + tabs?: HeaderTab[]; +} diff --git a/packages/canon/src/components/Icon/Icon.stories.tsx b/packages/ui/src/components/Icon/Icon.stories.tsx similarity index 100% rename from packages/canon/src/components/Icon/Icon.stories.tsx rename to packages/ui/src/components/Icon/Icon.stories.tsx diff --git a/packages/canon/src/components/Icon/Icon.tsx b/packages/ui/src/components/Icon/Icon.tsx similarity index 81% rename from packages/canon/src/components/Icon/Icon.tsx rename to packages/ui/src/components/Icon/Icon.tsx index 8877420a84..6f1e3d9c72 100644 --- a/packages/canon/src/components/Icon/Icon.tsx +++ b/packages/ui/src/components/Icon/Icon.tsx @@ -18,22 +18,25 @@ import { ComponentType } from 'react'; import { useIcons } from './context'; import type { IconProps } from './types'; import clsx from 'clsx'; +import { useStyles } from '../../hooks/useStyles'; /** @public */ export const Icon = (props: IconProps) => { const { name, size, className, style, ...restProps } = props; const { icons } = useIcons(); - const CanonIcon = icons[name] as ComponentType>; + const BckstageIcon = icons[name] as ComponentType>; - if (!CanonIcon) { + if (!BckstageIcon) { console.error(`Icon "${name}" not found or is not a valid component.`); return null; } + const { classNames } = useStyles('Icon'); + return ( - ( + + + + ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + href: '/', + children: 'Sign up for Backstage', + }, +}; + +export const ExternalLink: Story = { + args: { + href: 'https://backstage.io', + children: 'Sign up for Backstage', + target: '_blank', + }, +}; + +export const AllVariants: Story = { + args: { + ...Default.args, + }, + render: args => ( + + + + + + + + + + + ), +}; + +export const AllColors: Story = { + render: () => ( + + + + + + + + ), +}; + +export const AllWeights: Story = { + render: () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), +}; + +export const Truncate: 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?", + href: '/', + truncate: true, + style: { width: '480px' }, + }, +}; + +export const Responsive: Story = { + args: { + ...Default.args, + variant: { + xs: 'title-x-small', + md: 'body-x-small', + }, + }, +}; + +export const Playground: Story = { + args: { + ...Default.args, + }, + render: args => ( + + Title X Small + + Body X Small + + Body Small + + Body Medium + + Body Large + + Title Small + + Title Medium + + + ), +}; diff --git a/packages/ui/src/components/Link/Link.tsx b/packages/ui/src/components/Link/Link.tsx new file mode 100644 index 0000000000..fdbc961e19 --- /dev/null +++ b/packages/ui/src/components/Link/Link.tsx @@ -0,0 +1,98 @@ +/* + * Copyright 2024 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 { forwardRef } from 'react'; +import { Link as AriaLink, RouterProvider } from 'react-aria-components'; +import clsx from 'clsx'; +import { useStyles } from '../../hooks/useStyles'; +import type { LinkProps } from './types'; +import { useNavigate, useHref } from 'react-router-dom'; + +// Helper function to determine if a link is external +function isExternalLink(href?: string): boolean { + if (!href) return false; + + // Check if it's an absolute URL with protocol + if (href.startsWith('http://') || href.startsWith('https://')) { + return true; + } + + // Check if it's a protocol-relative URL + if (href.startsWith('//')) { + return true; + } + + // Check if it's a mailto: or tel: link + if (href.startsWith('mailto:') || href.startsWith('tel:')) { + return true; + } + + return false; +} + +/** @public */ +export const Link = forwardRef((props, ref) => { + const navigate = useNavigate(); + const { + className, + variant = 'body', + weight = 'regular', + color = 'primary', + truncate, + href, + ...restProps + } = props; + + const { classNames: linkClassNames } = useStyles('Link'); + const { classNames: textClassNames, dataAttributes: textDataAttributes } = + useStyles('Text', { + variant, + weight, + color, + }); + + const isExternal = isExternalLink(href); + + // If it's an external link, render AriaLink without RouterProvider + if (isExternal) { + return ( + + ); + } + + // For internal links, use RouterProvider + return ( + + + + ); +}); + +Link.displayName = 'Link'; diff --git a/packages/canon/src/components/Link/index.ts b/packages/ui/src/components/Link/index.ts similarity index 100% rename from packages/canon/src/components/Link/index.ts rename to packages/ui/src/components/Link/index.ts diff --git a/packages/ui/src/components/Link/styles.css b/packages/ui/src/components/Link/styles.css new file mode 100644 index 0000000000..76a56e2d7a --- /dev/null +++ b/packages/ui/src/components/Link/styles.css @@ -0,0 +1,32 @@ +/* + * Copyright 2024 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. + */ + +.bui-Link { + font-family: var(--bui-font-regular); + padding: 0; + margin: 0; + cursor: pointer; + text-decoration-line: none; + display: inline-block; + + &:hover { + text-decoration-line: underline; + text-decoration-style: solid; + text-decoration-thickness: min(2px, max(1px, 0.05em)); + text-underline-offset: calc(0.025em + 2px); + text-decoration-color: color-mix(in srgb, currentColor 30%, transparent); + } +} diff --git a/packages/ui/src/components/Link/types.ts b/packages/ui/src/components/Link/types.ts new file mode 100644 index 0000000000..33c33b26c0 --- /dev/null +++ b/packages/ui/src/components/Link/types.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { + Breakpoint, + TextColors, + TextColorStatus, + TextVariants, + TextWeights, +} from '../../types'; +import type { LinkProps as AriaLinkProps } from 'react-aria-components'; + +/** @public */ +export interface LinkProps extends AriaLinkProps { + variant?: TextVariants | Partial>; + weight?: TextWeights | Partial>; + color?: + | TextColors + | TextColorStatus + | Partial>; + truncate?: boolean; +} diff --git a/packages/canon/src/components/Menu/Combobox.tsx b/packages/ui/src/components/Menu/Combobox.tsx similarity index 93% rename from packages/canon/src/components/Menu/Combobox.tsx rename to packages/ui/src/components/Menu/Combobox.tsx index c9593ed2a4..2d74d52a40 100644 --- a/packages/canon/src/components/Menu/Combobox.tsx +++ b/packages/ui/src/components/Menu/Combobox.tsx @@ -27,7 +27,7 @@ import { } from 'react'; import clsx from 'clsx'; import { MenuComboboxOption, MenuComboboxProps } from './types'; -import { Icon } from '@backstage/canon'; +import { Icon } from '../..'; const getListboxItemId = (listboxId: string, optionValue: string): string => `${listboxId}-option-${optionValue}`; @@ -66,7 +66,7 @@ function ComboboxItem({ return (
!option.disabled && onItemActive(optionIndex)} onClick={() => !option.disabled && onItemSelect(option.value)} > -
+
{isSelected &&
-
{option.label}
+
{option.label}
); } @@ -194,11 +194,11 @@ export const Combobox = forwardRef(
( id={listboxId} tabIndex={-1} aria-multiselectable={multiselect ? true : undefined} - className="canon-SubmenuComboboxItems" + className="bui-SubmenuComboboxItems" > {filteredOptions.length === 0 ? ( -
- No results found -
+
No results found
) : ( filteredOptions.map((option, index) => ( - ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - - - - ), - }, + args: { children: undefined }, + render: args => ( + + ( + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + + + + ), }; export const Open: Story = { @@ -75,6 +74,7 @@ export const Open: Story = { ...Default.args, open: true, }, + render: Default.render, }; export const OpenOnHover: Story = { @@ -82,49 +82,49 @@ export const OpenOnHover: Story = { ...Default.args, openOnHover: true, }, + render: Default.render, }; export const Submenu: Story = { - args: { - children: ( - <> - ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - Submenu - - - - Submenu Item 1 - Submenu Item 2 - Submenu Item 3 - - - - - - - - - ), - }, + args: { children: undefined }, + render: args => ( + + ( + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + Submenu + + + + Submenu Item 1 + Submenu Item 2 + Submenu Item 3 + + + + + + + + + ), }; export const SubmenuCombobox = () => { diff --git a/packages/ui/src/components/Menu/Menu.styles.css b/packages/ui/src/components/Menu/Menu.styles.css new file mode 100644 index 0000000000..fe1275cb56 --- /dev/null +++ b/packages/ui/src/components/Menu/Menu.styles.css @@ -0,0 +1,182 @@ +.bui-MenuPositioner { + outline: 0; + z-index: 100; +} + +.bui-MenuPopup { + display: flex; + flex-direction: column; + border-radius: 0.375rem; + background-color: var(--bui-bg-surface-1); + border: 1px solid var(--bui-border); + color: var(--bui-fg-primary); + outline: none; + overflow: auto; + transform-origin: var(--transform-origin); + max-width: min(var(--available-width), 340px); + max-height: min(var(--available-height), 500px); + transition: transform 150ms, opacity 150ms; + position: relative; + padding-bottom: var(--bui-space-1); + + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } +} + +.bui-MenuItem { + outline: 0; + user-select: none; + display: flex; + height: 32px; + align-items: center; + gap: var(--bui-space-2); + color: var(--bui-fg-primary); + text-decoration: none; + border-radius: var(--bui-radius-2); + margin-inline: var(--bui-space-1); + padding-inline: var(--bui-space-2); + font-size: var(--bui-font-size-3); + cursor: pointer; + flex-shrink: 0; + + &:first-child { + margin-top: var(--bui-space-1); + } + + &[data-highlighted] { + background-color: var(--bui-gray-3); + } +} + +.bui-MenuSubmenuTrigger { + outline: 0; + user-select: none; + display: flex; + height: 32px; + align-items: center; + justify-content: space-between; + gap: var(--bui-space-2); + color: var(--bui-fg-primary); + text-decoration: none; + border-radius: var(--bui-radius-2); + margin-inline: var(--bui-space-1); + padding-inline: var(--bui-space-2); + font-size: var(--bui-font-size-3); + cursor: pointer; + flex-shrink: 0; + + & .bui-Icon { + color: var(--bui-fg-secondary); + } + + &:first-child { + margin-top: var(--bui-space-1); + } + + &[data-popup-open], + &[data-highlighted] { + background-color: var(--bui-gray-3); + + .bui-Icon { + color: var(--bui-fg-primary); + } + } +} + +.bui-MenuSeparator { + margin: 0.375rem 1rem; + height: 1px; + background-color: var(--color-gray-200); +} + +.bui-SubmenuComboboxSearch { + padding-inline: var(--bui-space-3); + width: 100%; + height: 32px; + border: none; + border-bottom: 1px solid var(--bui-border); + background-color: var(--bui-bg-surface-1); + color: var(--bui-fg-primary); + line-height: 140%; + outline: none; + font-size: var(--bui-font-size-3); + position: sticky; + top: 0; + z-index: 1; + + &::placeholder { + color: var(--bui-fg-secondary); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } +} + +.bui-SubmenuComboboxItems { + overflow-y: auto; + display: flex; + flex-direction: column; + padding-top: var(--bui-space-2); + outline: none; +} + +.bui-SubmenuComboboxNoResults { + padding-inline: var(--bui-space-3); + padding-top: var(--bui-space-2); + padding-bottom: var(--bui-space-4); + color: var(--bui-fg-secondary); + font-size: var(--bui-font-size-3); +} + +.bui-SubmenuComboboxItem { + outline: 0; + user-select: none; + display: flex; + height: 32px; + align-items: center; + justify-content: space-between; + gap: var(--bui-space-2); + color: var(--bui-fg-primary); + text-decoration: none; + border-radius: var(--bui-radius-2); + margin-inline: var(--bui-space-1); + padding-inline: var(--bui-space-2); + font-size: var(--bui-font-size-3); + cursor: pointer; + user-select: none; + flex-shrink: 0; + + &[data-highlighted] { + background-color: var(--bui-gray-3); + } + + &[data-disabled] { + opacity: 0.5; + cursor: not-allowed; + } +} + +.bui-SubmenuComboboxItemCheckbox { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: var(--bui-fg-primary); + flex-shrink: 0; + border-radius: var(--bui-radius-2); + border: 1px solid var(--bui-border); + background: var(--bui-bg-surface-1); +} + +.bui-SubmenuComboboxItemLabel { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/packages/canon/src/components/Menu/Menu.tsx b/packages/ui/src/components/Menu/Menu.tsx similarity index 56% rename from packages/canon/src/components/Menu/Menu.tsx rename to packages/ui/src/components/Menu/Menu.tsx index 123b01b283..9c475fdf5f 100644 --- a/packages/canon/src/components/Menu/Menu.tsx +++ b/packages/ui/src/components/Menu/Menu.tsx @@ -20,190 +20,255 @@ import clsx from 'clsx'; import { MenuComponent } from './types'; import { Combobox } from './Combobox'; import { Icon } from '../Icon'; +import { useStyles } from '../../hooks/useStyles'; const MenuTrigger = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuTrigger.displayName = MenuPrimitive.Trigger.displayName; const MenuBackdrop = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuBackdrop.displayName = MenuPrimitive.Backdrop.displayName; const MenuPositioner = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuPositioner.displayName = MenuPrimitive.Positioner.displayName; const MenuPopup = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuPopup.displayName = MenuPrimitive.Popup.displayName; const MenuArrow = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuArrow.displayName = MenuPrimitive.Arrow.displayName; const MenuItem = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuItem.displayName = MenuPrimitive.Item.displayName; const MenuGroup = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuGroup.displayName = MenuPrimitive.Group.displayName; const MenuGroupLabel = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuGroupLabel.displayName = MenuPrimitive.GroupLabel.displayName; const MenuRadioGroup = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuRadioGroup.displayName = MenuPrimitive.RadioGroup.displayName; const MenuRadioItem = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuRadioItem.displayName = MenuPrimitive.RadioItem.displayName; const MenuRadioItemIndicator = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuRadioItemIndicator.displayName = MenuPrimitive.RadioItemIndicator.displayName; const MenuCheckboxItem = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuCheckboxItem.displayName = MenuPrimitive.CheckboxItem.displayName; const MenuCheckboxItemIndicator = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuCheckboxItemIndicator.displayName = MenuPrimitive.CheckboxItemIndicator.displayName; const MenuSubmenuTrigger = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
- -
-)); +>(({ className, children, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + +
{children}
+ +
+ ); +}); MenuSubmenuTrigger.displayName = MenuPrimitive.SubmenuTrigger.displayName; const MenuSeparator = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Menu'); + + return ( + + ); +}); MenuSeparator.displayName = MenuPrimitive.Separator.displayName; /** @public */ diff --git a/packages/canon/src/components/Menu/index.ts b/packages/ui/src/components/Menu/index.ts similarity index 100% rename from packages/canon/src/components/Menu/index.ts rename to packages/ui/src/components/Menu/index.ts diff --git a/packages/canon/src/components/Menu/types.ts b/packages/ui/src/components/Menu/types.ts similarity index 100% rename from packages/canon/src/components/Menu/types.ts rename to packages/ui/src/components/Menu/types.ts diff --git a/packages/ui/src/components/Popover/Popover.styles.css b/packages/ui/src/components/Popover/Popover.styles.css new file mode 100644 index 0000000000..23ae5c1019 --- /dev/null +++ b/packages/ui/src/components/Popover/Popover.styles.css @@ -0,0 +1,25 @@ +/* + * Copyright 2024 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. + */ + +.bui-Popover { + margin-right: 12px; + overflow: scroll; + background-color: var(--bui-bg-surface-1); + border: 1px solid var(--bui-border); + border-radius: var(--bui-radius-3); + padding-block: var(--bui-space-1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} diff --git a/packages/canon/src/components/RadioGroup/RadioGroup.stories.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx similarity index 100% rename from packages/canon/src/components/RadioGroup/RadioGroup.stories.tsx rename to packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx diff --git a/packages/ui/src/components/RadioGroup/RadioGroup.styles.css b/packages/ui/src/components/RadioGroup/RadioGroup.styles.css new file mode 100644 index 0000000000..f12d5571e0 --- /dev/null +++ b/packages/ui/src/components/RadioGroup/RadioGroup.styles.css @@ -0,0 +1,95 @@ +.bui-RadioGroup { + display: flex; + flex-direction: column; + color: var(--bui-fg-primary); +} + +.bui-RadioGroup[data-orientation='horizontal'] .bui-RadioGroupContent { + flex-direction: row; + gap: var(--bui-space-4); +} + +.bui-RadioGroupContent { + display: flex; + flex-direction: column; + gap: var(--bui-space-2); +} + +.bui-Radio { + display: flex; + /* This is needed so the HiddenInput is positioned correctly */ + position: relative; + align-items: center; + gap: var(--bui-space-2); + font-size: var(--bui-font-size-2); + color: var(--bui-fg-primary); + forced-color-adjust: none; + + &:before { + content: ''; + display: block; + width: 1rem; + height: 1rem; + box-sizing: border-box; + border: 0.125rem solid var(--bui-border); + background: var(--bui-gray-1); + border-radius: var(--bui-radius-full); + transition: all 200ms; + } + + &[data-pressed]:before { + border-color: var(--bui-border); + } + + &[data-selected] { + &:before { + border-color: var(--bui-bg-solid); + border-width: 0.25rem; + } + + &[data-pressed]:before { + border-color: var(--bui-bg-solid); + } + } + + &[data-focus-visible]:before { + outline: 2px solid var(--bui-ring); + outline-offset: 2px; + } + + &[data-disabled] { + cursor: not-allowed; + color: var(--bui-fg-disabled); + + &:before { + border-color: var(--bui-border-disabled); + background: var(--bui-bg-disabled); + } + + &[data-selected]:before { + border-color: var(--bui-border-disabled); + } + } + + &[data-invalid]:before { + border-color: var(--bui-border-danger); + } + + &[data-invalid][data-selected]:before { + border-color: var(--bui-border-danger); + } + + /* Ensure disabled state prevails over invalid state */ + &[data-disabled][data-invalid] { + color: var(--bui-fg-disabled); + + &:before { + border-color: var(--bui-border-disabled); + background: var(--bui-bg-disabled); + } + + &[data-selected]:before { + border-color: var(--bui-border-disabled); + } + } +} diff --git a/packages/canon/src/components/RadioGroup/RadioGroup.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.tsx similarity index 85% rename from packages/canon/src/components/RadioGroup/RadioGroup.tsx rename to packages/ui/src/components/RadioGroup/RadioGroup.tsx index d1d7451a92..4363477c1a 100644 --- a/packages/canon/src/components/RadioGroup/RadioGroup.tsx +++ b/packages/ui/src/components/RadioGroup/RadioGroup.tsx @@ -22,6 +22,7 @@ import { import clsx from 'clsx'; import { FieldLabel } from '../FieldLabel'; import { FieldError } from '../FieldError'; +import { useStyles } from '../../hooks/useStyles'; import type { RadioGroupProps, RadioProps } from './types'; @@ -40,6 +41,8 @@ export const RadioGroup = forwardRef( ...rest } = props; + const { classNames } = useStyles('RadioGroup'); + useEffect(() => { if (!label && !ariaLabel && !ariaLabelledBy) { console.warn( @@ -54,7 +57,7 @@ export const RadioGroup = forwardRef( return ( ( secondaryLabel={secondaryLabelText} description={description} /> -
{children}
+
{children}
); @@ -78,8 +81,14 @@ RadioGroup.displayName = 'RadioGroup'; export const Radio = forwardRef((props, ref) => { const { className, ...rest } = props; + const { classNames } = useStyles('RadioGroup'); + return ( - + ); }); diff --git a/packages/canon/src/components/RadioGroup/index.ts b/packages/ui/src/components/RadioGroup/index.ts similarity index 100% rename from packages/canon/src/components/RadioGroup/index.ts rename to packages/ui/src/components/RadioGroup/index.ts diff --git a/packages/canon/src/components/RadioGroup/types.ts b/packages/ui/src/components/RadioGroup/types.ts similarity index 100% rename from packages/canon/src/components/RadioGroup/types.ts rename to packages/ui/src/components/RadioGroup/types.ts diff --git a/packages/canon/src/components/ScrollArea/ScrollArea.stories.tsx b/packages/ui/src/components/ScrollArea/ScrollArea.stories.tsx similarity index 97% rename from packages/canon/src/components/ScrollArea/ScrollArea.stories.tsx rename to packages/ui/src/components/ScrollArea/ScrollArea.stories.tsx index 25a3d5f3d8..867ce29b07 100644 --- a/packages/canon/src/components/ScrollArea/ScrollArea.stories.tsx +++ b/packages/ui/src/components/ScrollArea/ScrollArea.stories.tsx @@ -30,7 +30,7 @@ export const Default: Story = { render: () => (
diff --git a/packages/canon/src/components/ScrollArea/ScrollArea.styles.css b/packages/ui/src/components/ScrollArea/ScrollArea.styles.css similarity index 80% rename from packages/canon/src/components/ScrollArea/ScrollArea.styles.css rename to packages/ui/src/components/ScrollArea/ScrollArea.styles.css index 1d1c25e9d0..209168c329 100644 --- a/packages/canon/src/components/ScrollArea/ScrollArea.styles.css +++ b/packages/ui/src/components/ScrollArea/ScrollArea.styles.css @@ -14,19 +14,17 @@ * limitations under the License. */ -.canon-ScrollAreaRoot { +.bui-ScrollAreaRoot { box-sizing: border-box; - width: 24rem; - height: 8.5rem; - max-width: calc(100vw - 8rem); + width: 100%; } -.canon-ScrollAreaViewport { +.bui-ScrollAreaViewport { height: 100%; overscroll-behavior: contain; } -.canon-ScrollAreaContent { +.bui-ScrollAreaContent { display: flex; flex-direction: column; gap: 1rem; @@ -35,10 +33,10 @@ padding-right: 1.5rem; } -.canon-ScrollAreaScrollbar { +.bui-ScrollAreaScrollbar { display: flex; justify-content: center; - background-color: var(--canon-scrollbar); + background-color: var(--bui-scrollbar); width: 0.25rem; border-radius: 0.375rem; margin: 0.5rem; @@ -60,8 +58,8 @@ } } -.canon-ScrollAreaThumb { +.bui-ScrollAreaThumb { width: 100%; border-radius: inherit; - background-color: var(--canon-scrollbar-thumb); + background-color: var(--bui-scrollbar-thumb); } diff --git a/packages/canon/src/components/ScrollArea/ScrollArea.tsx b/packages/ui/src/components/ScrollArea/ScrollArea.tsx similarity index 65% rename from packages/canon/src/components/ScrollArea/ScrollArea.tsx rename to packages/ui/src/components/ScrollArea/ScrollArea.tsx index e96e76c29b..44722fbd12 100644 --- a/packages/canon/src/components/ScrollArea/ScrollArea.tsx +++ b/packages/ui/src/components/ScrollArea/ScrollArea.tsx @@ -17,53 +17,70 @@ import { forwardRef } from 'react'; import { ScrollArea as ScrollAreaPrimitive } from '@base-ui-components/react/scroll-area'; import clsx from 'clsx'; +import { useStyles } from '../../hooks/useStyles'; const ScrollAreaRoot = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('ScrollArea'); + + return ( + + ); +}); ScrollAreaRoot.displayName = ScrollAreaPrimitive.Root.displayName; const ScrollAreaViewport = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('ScrollArea'); + + return ( + + ); +}); ScrollAreaViewport.displayName = ScrollAreaPrimitive.Viewport.displayName; const ScrollAreaScrollbar = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('ScrollArea'); + + return ( + + ); +}); ScrollAreaScrollbar.displayName = ScrollAreaPrimitive.Scrollbar.displayName; const ScrollAreaThumb = forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('ScrollArea'); + + return ( + + ); +}); ScrollAreaThumb.displayName = ScrollAreaPrimitive.Thumb.displayName; /** @public */ diff --git a/packages/canon/src/components/ScrollArea/index.ts b/packages/ui/src/components/ScrollArea/index.ts similarity index 100% rename from packages/canon/src/components/ScrollArea/index.ts rename to packages/ui/src/components/ScrollArea/index.ts diff --git a/packages/ui/src/components/SearchField/SearchField.stories.tsx b/packages/ui/src/components/SearchField/SearchField.stories.tsx new file mode 100644 index 0000000000..5b267f585d --- /dev/null +++ b/packages/ui/src/components/SearchField/SearchField.stories.tsx @@ -0,0 +1,154 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj } from '@storybook/react'; +import { SearchField } from './SearchField'; +import { Form } from 'react-aria-components'; +import { Icon } from '../Icon'; +import { Flex } from '../Flex'; +import { FieldLabel } from '../FieldLabel'; + +const meta = { + title: 'Forms/SearchField', + component: SearchField, + argTypes: { + isRequired: { + control: 'boolean', + }, + icon: { + control: 'object', + }, + placeholder: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + name: 'url', + style: { + maxWidth: '300px', + }, + }, +}; + +export const Sizes: Story = { + args: { + ...Default.args, + }, + render: args => ( + + + + + ), +}; + +export const DefaultValue: Story = { + args: { + ...Default.args, + defaultValue: 'https://example.com', + }, +}; + +export const WithLabel: Story = { + args: { + ...Default.args, + label: 'Label', + }, +}; + +export const WithDescription: Story = { + args: { + ...WithLabel.args, + description: 'Description', + }, +}; + +export const Required: Story = { + args: { + ...WithLabel.args, + isRequired: true, + }, +}; + +export const Disabled: Story = { + args: { + ...Default.args, + isDisabled: true, + }, +}; + +export const WithIcon: Story = { + args: { + ...Default.args, + }, + render: args => ( + } + /> + ), +}; + +export const DisabledWithIcon: Story = { + args: { + ...WithIcon.args, + isDisabled: true, + }, +}; + +export const ShowError: Story = { + args: { + ...WithLabel.args, + }, + render: args => ( +
+ + + ), +}; + +export const Validation: Story = { + args: { + ...WithLabel.args, + validate: value => (value === 'admin' ? 'Nice try!' : null), + }, +}; + +export const CustomField: Story = { + render: () => ( + <> + + + + ), +}; diff --git a/packages/ui/src/components/SearchField/SearchField.styles.css b/packages/ui/src/components/SearchField/SearchField.styles.css new file mode 100644 index 0000000000..f2f808c5e0 --- /dev/null +++ b/packages/ui/src/components/SearchField/SearchField.styles.css @@ -0,0 +1,55 @@ +/* + * Copyright 2024 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. + */ + +.bui-SearchField[data-empty] .bui-InputClear { + display: none; +} + +.bui-InputClear { + position: absolute; + right: 0; + top: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background-color: transparent; + border: none; + padding: 0; + margin: 0; + cursor: pointer; + color: var(--bui-fg-secondary); + transition: color 0.2s ease-in-out; +} + +.bui-InputClear:hover { + color: var(--bui-fg-primary); +} + +.bui-InputClear[data-size='small'] { + width: 2rem; + height: 2rem; +} + +.bui-InputClear[data-size='medium'] { + width: 2.5rem; + height: 2.5rem; +} + +.bui-InputClear svg { + width: 1rem; + height: 1rem; +} diff --git a/packages/ui/src/components/SearchField/SearchField.tsx b/packages/ui/src/components/SearchField/SearchField.tsx new file mode 100644 index 0000000000..ff54439309 --- /dev/null +++ b/packages/ui/src/components/SearchField/SearchField.tsx @@ -0,0 +1,120 @@ +/* + * Copyright 2024 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 { forwardRef, useEffect } from 'react'; +import { + Input, + SearchField as AriaSearchField, + Button, +} from 'react-aria-components'; +import clsx from 'clsx'; +import { FieldLabel } from '../FieldLabel'; +import { FieldError } from '../FieldError'; +import { RiSearch2Line, RiCloseCircleLine } from '@remixicon/react'; +import { useStyles } from '../../hooks/useStyles'; + +import type { SearchFieldProps } from './types'; + +/** @public */ +export const SearchField = forwardRef( + (props, ref) => { + const { + className, + icon, + size = 'small', + label, + secondaryLabel, + description, + isRequired, + placeholder = 'Search', + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + ...rest + } = props; + + useEffect(() => { + if (!label && !ariaLabel && !ariaLabelledBy) { + console.warn( + 'SearchField requires either a visible label, aria-label, or aria-labelledby for accessibility', + ); + } + }, [label, ariaLabel, ariaLabelledBy]); + + const { classNames: textFieldClassNames, dataAttributes } = useStyles( + 'TextField', + { + size, + }, + ); + + const { classNames: searchFieldClassNames } = useStyles('SearchField', { + size, + }); + + // If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required. + const secondaryLabelText = + secondaryLabel || (isRequired ? 'Required' : null); + + return ( + + +
+ {icon !== false && ( + + )} + + +
+ +
+ ); + }, +); + +SearchField.displayName = 'searchField'; diff --git a/packages/canon/src/components/Heading/index.ts b/packages/ui/src/components/SearchField/index.ts similarity index 95% rename from packages/canon/src/components/Heading/index.ts rename to packages/ui/src/components/SearchField/index.ts index ca9845b122..288c3fe44a 100644 --- a/packages/canon/src/components/Heading/index.ts +++ b/packages/ui/src/components/SearchField/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export * from './Heading'; +export * from './SearchField'; export * from './types'; diff --git a/packages/ui/src/components/SearchField/types.ts b/packages/ui/src/components/SearchField/types.ts new file mode 100644 index 0000000000..b561292684 --- /dev/null +++ b/packages/ui/src/components/SearchField/types.ts @@ -0,0 +1,41 @@ +/* + * 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 type { SearchFieldProps as AriaSearchFieldProps } from 'react-aria-components'; +import { ReactNode } from 'react'; +import type { Breakpoint } from '../../types'; +import type { FieldLabelProps } from '../FieldLabel/types'; + +/** @public */ +export interface SearchFieldProps + extends AriaSearchFieldProps, + Omit { + /** + * An icon to render before the input + */ + icon?: ReactNode | false; + + /** + * The size of the text field + * @defaultValue 'medium' + */ + size?: 'small' | 'medium' | Partial>; + + /** + * The placeholder text for the input + */ + placeholder?: string; +} diff --git a/packages/canon/src/components/Select/Select.stories.tsx b/packages/ui/src/components/Select/Select.stories.tsx similarity index 83% rename from packages/canon/src/components/Select/Select.stories.tsx rename to packages/ui/src/components/Select/Select.stories.tsx index 000ba180dc..ecefc6ec09 100644 --- a/packages/canon/src/components/Select/Select.stories.tsx +++ b/packages/ui/src/components/Select/Select.stories.tsx @@ -16,9 +16,11 @@ import type { Meta, StoryObj } from '@storybook/react'; import { Select } from './Select'; import { Flex } from '../Flex'; +import { Form } from 'react-aria-components'; +import { RiCloudLine } from '@remixicon/react'; const meta = { - title: 'Components/Select', + title: 'Forms/Select', component: Select, } satisfies Meta; @@ -49,21 +51,35 @@ export const Preview: Story = { }, }; -export const WithDescription: Story = { +export const WithLabel: Story = { args: { - ...Preview.args, + ...Default.args, + label: 'Font Family', + }, +}; + +export const WithLabelAndDescription: Story = { + args: { + ...WithLabel.args, description: 'Choose a font family for your document', }, }; +export const WithIcon: Story = { + args: { + ...WithLabel.args, + }, + render: args => - } /> + + + ), }; -export const WithLongOptionNames: Story = { +export const WithLongNames: Story = { args: { label: 'Document Template', options: [ @@ -286,6 +304,19 @@ export const WithLongOptionNames: Story = { placeholder: 'Select a document template', name: 'template', style: { maxWidth: 400 }, - value: 'annual-report-2024', + defaultSelectedKey: 'annual-report-2024', }, }; + +export const WithLongNamesAndPadding: Story = { + args: { + ...WithLongNames.args, + }, + decorators: [ + (Story, { args }) => ( +
+ +
+ ), + ], +}; diff --git a/packages/ui/src/components/Select/Select.styles.css b/packages/ui/src/components/Select/Select.styles.css new file mode 100644 index 0000000000..da700d67d1 --- /dev/null +++ b/packages/ui/src/components/Select/Select.styles.css @@ -0,0 +1,173 @@ +/* + * Copyright 2024 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. + */ + +.bui-Select[data-invalid] { + & .bui-SelectTrigger { + border-color: var(--bui-fg-danger); + } +} + +.bui-SelectTrigger { + box-sizing: border-box; + border-radius: var(--bui-radius-3); + border: 1px solid var(--bui-border); + background-color: var(--bui-bg-surface-1); + display: flex; + justify-content: space-between; + align-items: center; + transition: border-color 0.2s ease-in-out, outline-color 0.2s ease-in-out; + cursor: pointer; + gap: var(--bui-space-2); + max-width: 100%; + + & svg { + flex-shrink: 0; + } + + &[data-size='small'] { + height: 2rem; + padding-inline: var(--bui-space-3); + } + + &[data-size='medium'] { + height: 3rem; + padding-inline: var(--bui-space-4); + } + + &[data-size='small'] svg { + width: 1rem; + height: 1rem; + } + + &[data-size='medium'] svg { + width: 1.25rem; + height: 1.25rem; + } + + &::placeholder { + color: var(--bui-fg-secondary); + } + + &:hover { + border-color: var(--bui-border-hover); + } + + &:focus-visible { + border-color: var(--bui-border-pressed); + outline: 0; + } + + &[data-invalid] { + border-color: var(--bui-fg-danger); + } + &[data-invalid]:hover { + border-width: 2px; + } + + &[data-invalid]:focus-visible { + border-width: 2px; + } + + &[disabled] { + cursor: not-allowed; + border-color: var(--bui-border-disabled); + color: var(--bui-fg-disabled); + } + + &[disabled] .bui-SelectValue { + color: var(--bui-fg-disabled); + } + + &[data-popup-open] .bui-SelectIcon { + transform: rotate(180deg); + } +} + +.bui-SelectValue { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + width: 100%; + font-size: var(--bui-font-size-3); + font-family: var(--bui-font-regular); + font-weight: var(--bui-font-weight-regular); + color: var(--bui-fg-primary); + + & .bui-SelectItemIndicator { + display: none; + } + + &[disabled] { + color: var(--bui-fg-disabled); + } +} + +.bui-SelectItem { + position: relative; + width: var(--anchor-width); + display: grid; + grid-template-areas: 'icon text'; + grid-template-columns: 1rem 1fr; + align-items: center; + padding-block: var(--bui-space-2); + padding-inline: var(--bui-space-4); + color: var(--bui-fg-primary); + border-radius: var(--bui-radius-3); + cursor: pointer; + user-select: none; + font-size: var(--bui-font-size-3); + gap: var(--bui-space-2); + outline: none; + + &[data-focused] { + z-index: 0; + position: relative; + color: var(--bui-fg-primary); + } + + &[data-focused]::before { + content: ''; + z-index: -1; + position: absolute; + inset-block: 0; + inset-inline: 0.25rem; + border-radius: 0.25rem; + background-color: var(--bui-bg-tint-hover); + } + + &[data-disabled] { + cursor: not-allowed; + color: var(--bui-fg-disabled); + } + + &[data-selected] .bui-SelectItemIndicator { + opacity: 1; + } +} + +.bui-SelectItemIndicator { + grid-area: icon; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s ease-in-out; +} + +.bui-SelectItemLabel { + flex: 1; + grid-area: text; +} diff --git a/packages/ui/src/components/Select/Select.tsx b/packages/ui/src/components/Select/Select.tsx new file mode 100644 index 0000000000..ce3e094b9d --- /dev/null +++ b/packages/ui/src/components/Select/Select.tsx @@ -0,0 +1,112 @@ +/* + * Copyright 2024 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 { forwardRef, useEffect } from 'react'; +import { + Select as AriaSelect, + SelectValue, + Button, + Popover, + ListBox, + ListBoxItem, + Text, +} from 'react-aria-components'; +import clsx from 'clsx'; +import './Select.styles.css'; +import { SelectProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; +import { FieldLabel } from '../FieldLabel'; +import { Icon } from '../Icon'; +import { FieldError } from '../FieldError'; + +/** @public */ +export const Select = forwardRef((props, ref) => { + const { + className, + label, + description, + options, + placeholder = 'Select an option', + size = 'small', + icon, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + isRequired, + secondaryLabel, + style, + ...rest + } = props; + + const { classNames: popoverClassNames } = useStyles('Popover'); + const { classNames, dataAttributes } = useStyles('Select', { + size, + }); + + useEffect(() => { + if (!label && !ariaLabel && !ariaLabelledBy) { + console.warn( + 'TextField requires either a visible label, aria-label, or aria-labelledby for accessibility', + ); + } + }, [label, ariaLabel, ariaLabelledBy]); + + // If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required. + const secondaryLabelText = secondaryLabel || (isRequired ? 'Required' : null); + + return ( + + + + + + + {options?.map(option => ( + +
+ +
+ + {option.label} + +
+ ))} +
+
+
+ ); +}); + +Select.displayName = 'Select'; diff --git a/packages/canon/src/components/Select/index.ts b/packages/ui/src/components/Select/index.ts similarity index 100% rename from packages/canon/src/components/Select/index.ts rename to packages/ui/src/components/Select/index.ts diff --git a/packages/ui/src/components/Select/types.ts b/packages/ui/src/components/Select/types.ts new file mode 100644 index 0000000000..6aea3452cc --- /dev/null +++ b/packages/ui/src/components/Select/types.ts @@ -0,0 +1,44 @@ +/* + * 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 { Breakpoint } from '../..'; +import { ReactNode } from 'react'; +import type { SelectProps as AriaSelectProps } from 'react-aria-components'; +import type { FieldLabelProps } from '../FieldLabel/types'; + +/** @public */ +export interface SelectProps + extends AriaSelectProps<{ + name: string; + value: string; + }>, + Omit { + /** + * An icon to render before the input + */ + icon?: ReactNode; + + /** + * The size of the select field + * @defaultValue 'medium' + */ + size?: 'small' | 'medium' | Partial>; + + /** + * The options of the select field + */ + options?: Array<{ value: string; label: string; disabled?: boolean }>; +} diff --git a/packages/ui/src/components/Skeleton/Skeleton.stories.tsx b/packages/ui/src/components/Skeleton/Skeleton.stories.tsx new file mode 100644 index 0000000000..3fe95c53bc --- /dev/null +++ b/packages/ui/src/components/Skeleton/Skeleton.stories.tsx @@ -0,0 +1,82 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { Skeleton } from './Skeleton'; +import { Flex } from '../Flex'; + +const meta = { + title: 'Components/Skeleton', + component: Skeleton, + argTypes: { + rounded: { + control: 'boolean', + }, + width: { + control: 'number', + }, + height: { + control: 'number', + }, + }, + args: { + width: 80, + height: 24, + rounded: false, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; + +export const Rounded: Story = { + args: { + rounded: true, + width: 48, + height: 48, + }, +}; + +export const Demo1: Story = { + render: () => ( + + + + + + + + + + + + + ), +}; + +export const Demo2: Story = { + render: () => ( + + + + + + ), +}; diff --git a/packages/ui/src/components/Skeleton/Skeleton.styles.css b/packages/ui/src/components/Skeleton/Skeleton.styles.css new file mode 100644 index 0000000000..bbbb6deaeb --- /dev/null +++ b/packages/ui/src/components/Skeleton/Skeleton.styles.css @@ -0,0 +1,25 @@ +/* + * Copyright 2024 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. + */ + +.bui-Skeleton { + animation: var(--bui-animate-pulse); + background-color: var(--bui-bg-surface-2); + border-radius: var(--bui-radius-2); +} + +.bui-Skeleton[data-rounded='true'] { + border-radius: var(--bui-radius-full); +} diff --git a/packages/ui/src/components/Skeleton/Skeleton.tsx b/packages/ui/src/components/Skeleton/Skeleton.tsx new file mode 100644 index 0000000000..772a69bc28 --- /dev/null +++ b/packages/ui/src/components/Skeleton/Skeleton.tsx @@ -0,0 +1,36 @@ +/* + * Copyright 2024 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 { useStyles } from '../../hooks/useStyles'; +import { SkeletonProps } from './types'; + +/** @public */ +export const Skeleton = (props: SkeletonProps) => { + const { width = 80, height = 24, rounded = false, ...rest } = props; + const { classNames } = useStyles('Skeleton'); + + return ( +
+ ); +}; diff --git a/packages/canon/src/components/Tooltip/index.ts b/packages/ui/src/components/Skeleton/index.tsx similarity index 87% rename from packages/canon/src/components/Tooltip/index.ts rename to packages/ui/src/components/Skeleton/index.tsx index cf97688854..f1e76b1851 100644 --- a/packages/canon/src/components/Tooltip/index.ts +++ b/packages/ui/src/components/Skeleton/index.tsx @@ -14,4 +14,5 @@ * limitations under the License. */ -export * from './Tooltip'; +export { Skeleton } from './Skeleton'; +export type { SkeletonProps } from './types'; diff --git a/packages/ui/src/components/Skeleton/types.ts b/packages/ui/src/components/Skeleton/types.ts new file mode 100644 index 0000000000..136873ed27 --- /dev/null +++ b/packages/ui/src/components/Skeleton/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 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 { ComponentProps } from 'react'; + +/** @public */ +export interface SkeletonProps extends ComponentProps<'div'> { + width?: number | string; + height?: number | string; + rounded?: boolean; +} diff --git a/packages/canon/src/components/Switch/Switch.stories.tsx b/packages/ui/src/components/Switch/Switch.stories.tsx similarity index 100% rename from packages/canon/src/components/Switch/Switch.stories.tsx rename to packages/ui/src/components/Switch/Switch.stories.tsx diff --git a/packages/canon/src/components/Switch/Switch.styles.css b/packages/ui/src/components/Switch/Switch.styles.css similarity index 71% rename from packages/canon/src/components/Switch/Switch.styles.css rename to packages/ui/src/components/Switch/Switch.styles.css index 98368efa13..ee2a24d013 100644 --- a/packages/canon/src/components/Switch/Switch.styles.css +++ b/packages/ui/src/components/Switch/Switch.styles.css @@ -14,50 +14,50 @@ * limitations under the License. */ -.canon-Switch { +.bui-Switch { display: flex; /* This is needed so the HiddenInput is positioned correctly */ position: relative; align-items: center; - gap: var(--canon-space-3); - font-size: var(--canon-font-size-3); - color: var(--canon-fg-primary); + gap: var(--bui-space-3); + font-size: var(--bui-font-size-3); + color: var(--bui-fg-primary); cursor: pointer; - &[data-pressed] .canon-SwitchIndicator { + &[data-pressed] .bui-SwitchIndicator { &:before { - background: var(--canon-fg-solid); + background: var(--bui-fg-solid); } } &[data-selected] { - .canon-SwitchIndicator { - background: var(--canon-bg-solid); + .bui-SwitchIndicator { + background: var(--bui-bg-solid); &:before { - background: var(--canon-fg-solid); + background: var(--bui-fg-solid); transform: translateX(100%); } } &[data-pressed] { .indicator { - background: var(--canon-gray-3); + background: var(--bui-gray-3); } } } - &[data-focus-visible] .canon-SwitchIndicator { + &[data-focus-visible] .bui-SwitchIndicator { outline: 2px solid; outline-offset: 2px; } } -.canon-SwitchIndicator { +.bui-SwitchIndicator { width: 2rem; height: 1.143rem; border: 2px; - background: var(--canon-gray-3); + background: var(--bui-gray-3); border-radius: 1.143rem; transition: all 200ms; @@ -67,7 +67,7 @@ margin: 0.143rem; width: 0.857rem; height: 0.857rem; - background: var(--canon-fg-solid); + background: var(--bui-fg-solid); border-radius: 16px; transition: all 200ms; } diff --git a/packages/canon/src/components/Switch/Switch.tsx b/packages/ui/src/components/Switch/Switch.tsx similarity index 81% rename from packages/canon/src/components/Switch/Switch.tsx rename to packages/ui/src/components/Switch/Switch.tsx index 78bbaa3930..70890ca3a0 100644 --- a/packages/canon/src/components/Switch/Switch.tsx +++ b/packages/ui/src/components/Switch/Switch.tsx @@ -17,13 +17,16 @@ import { forwardRef } from 'react'; import { Switch as AriaSwitch } from 'react-aria-components'; import type { SwitchProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; /** @public */ export const Switch = forwardRef( ({ label, ...props }, ref) => { + const { classNames } = useStyles('Switch'); + return ( - -
+ +
{label} ); diff --git a/packages/canon/src/components/Switch/index.tsx b/packages/ui/src/components/Switch/index.tsx similarity index 100% rename from packages/canon/src/components/Switch/index.tsx rename to packages/ui/src/components/Switch/index.tsx diff --git a/packages/canon/src/components/Switch/types.ts b/packages/ui/src/components/Switch/types.ts similarity index 100% rename from packages/canon/src/components/Switch/types.ts rename to packages/ui/src/components/Switch/types.ts diff --git a/packages/canon/src/components/Table/Table.stories.tsx b/packages/ui/src/components/Table/Table.stories.tsx similarity index 98% rename from packages/canon/src/components/Table/Table.stories.tsx rename to packages/ui/src/components/Table/Table.stories.tsx index e28e7e41d0..f008e73bae 100644 --- a/packages/canon/src/components/Table/Table.stories.tsx +++ b/packages/ui/src/components/Table/Table.stories.tsx @@ -16,7 +16,7 @@ import { ComponentType } from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { Table } from '../Table'; +import { Table } from '.'; const invoices = [ { diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/ui/src/components/Table/Table.tsx similarity index 64% rename from packages/canon/src/components/Table/Table.tsx rename to packages/ui/src/components/Table/Table.tsx index abc0ce03c8..ca89cae0c0 100644 --- a/packages/canon/src/components/Table/Table.tsx +++ b/packages/ui/src/components/Table/Table.tsx @@ -20,63 +20,88 @@ import { TableCell } from './TableCell/TableCell'; import { TableCellText } from './TableCellText/TableCellText'; import { TableCellLink } from './TableCellLink/TableCellLink'; import { TableCellProfile } from './TableCellProfile/TableCellProfile'; +import { useStyles } from '../../hooks/useStyles'; const TableRoot = forwardRef< HTMLTableElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( +
+ ); +}); TableRoot.displayName = 'TableRoot'; const TableHeader = forwardRef< HTMLTableSectionElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + ); +}); TableHeader.displayName = 'TableHeader'; const TableBody = forwardRef< HTMLTableSectionElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + ); +}); TableBody.displayName = 'TableBody'; const TableRow = forwardRef< HTMLTableRowElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( - - {props.children} - -)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + {props.children} + + ); +}); TableRow.displayName = 'TableRow'; const TableHead = forwardRef< HTMLTableCellElement, React.ThHTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + ); +}); TableHead.displayName = 'TableHead'; const TableCaption = forwardRef< HTMLTableCaptionElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + ); +}); TableCaption.displayName = 'TableCaption'; /** diff --git a/packages/canon/src/components/Table/TableCell/TableCell.stories.tsx b/packages/ui/src/components/Table/TableCell/TableCell.stories.tsx similarity index 100% rename from packages/canon/src/components/Table/TableCell/TableCell.stories.tsx rename to packages/ui/src/components/Table/TableCell/TableCell.stories.tsx diff --git a/packages/canon/src/components/Table/TableCell/TableCell.styles.css b/packages/ui/src/components/Table/TableCell/TableCell.styles.css similarity index 86% rename from packages/canon/src/components/Table/TableCell/TableCell.styles.css rename to packages/ui/src/components/Table/TableCell/TableCell.styles.css index 26d0868b49..dd3857d6f8 100644 --- a/packages/canon/src/components/Table/TableCell/TableCell.styles.css +++ b/packages/ui/src/components/Table/TableCell/TableCell.styles.css @@ -14,7 +14,7 @@ * limitations under the License. */ -.canon-TableCell { - padding: var(--canon-space-3); - font-size: var(--canon-font-size-3); +.bui-TableCell { + padding: var(--bui-space-3); + font-size: var(--bui-font-size-3); } diff --git a/packages/canon/src/components/Table/TableCell/TableCell.tsx b/packages/ui/src/components/Table/TableCell/TableCell.tsx similarity index 79% rename from packages/canon/src/components/Table/TableCell/TableCell.tsx rename to packages/ui/src/components/Table/TableCell/TableCell.tsx index a8a87ac038..cbd025178c 100644 --- a/packages/canon/src/components/Table/TableCell/TableCell.tsx +++ b/packages/ui/src/components/Table/TableCell/TableCell.tsx @@ -16,14 +16,19 @@ import { forwardRef } from 'react'; import clsx from 'clsx'; +import { useStyles } from '../../../hooks/useStyles'; /** @public */ const TableCell = forwardRef< HTMLTableCellElement, React.TdHTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); +>(({ className, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( + + ); +}); TableCell.displayName = 'TableCell'; export { TableCell }; diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx b/packages/ui/src/components/Table/TableCellLink/TableCellLink.stories.tsx similarity index 79% rename from packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx rename to packages/ui/src/components/Table/TableCellLink/TableCellLink.stories.tsx index 861f2643b2..bc9b66f18a 100644 --- a/packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx +++ b/packages/ui/src/components/Table/TableCellLink/TableCellLink.stories.tsx @@ -14,12 +14,20 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryFn, StoryObj } from '@storybook/react'; import { TableCellLink } from './TableCellLink'; +import { MemoryRouter } from 'react-router-dom'; const meta = { title: 'Components/Table/TableCellLink', component: TableCellLink, + decorators: [ + (Story: StoryFn) => ( + + + + ), + ], } satisfies Meta; export default meta; @@ -28,7 +36,7 @@ type Story = StoryObj; export const Default: Story = { args: { title: 'I am a link', - href: 'https://canon.backstage.io', + href: 'https://ui.backstage.io', }, }; diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css b/packages/ui/src/components/Table/TableCellLink/TableCellLink.styles.css similarity index 92% rename from packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css rename to packages/ui/src/components/Table/TableCellLink/TableCellLink.styles.css index 3064bbb791..d4e10631fe 100644 --- a/packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css +++ b/packages/ui/src/components/Table/TableCellLink/TableCellLink.styles.css @@ -14,8 +14,8 @@ * limitations under the License. */ -.canon-TableCellLink { +.bui-TableCellLink { display: flex; flex-direction: column; - gap: var(--canon-space-0_5); + gap: var(--bui-space-0_5); } diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx b/packages/ui/src/components/Table/TableCellLink/TableCellLink.tsx similarity index 69% rename from packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx rename to packages/ui/src/components/Table/TableCellLink/TableCellLink.tsx index cb9d3e69a8..e27a37977f 100644 --- a/packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx +++ b/packages/ui/src/components/Table/TableCellLink/TableCellLink.tsx @@ -19,27 +19,28 @@ import clsx from 'clsx'; import { TableCellLinkProps } from './types'; import { Text } from '../../Text/Text'; import { Link } from '../../Link/Link'; +import { useStyles } from '../../../hooks/useStyles'; /** @public */ const TableCellLink = forwardRef( - ({ className, title, description, href, render, ...props }, ref) => ( -
- {title && ( - - {title} - - )} - {description && ( - - {description} - - )} -
- ), + ({ className, title, description, href, render, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( +
+ {title && {title}} + {description && ( + + {description} + + )} +
+ ); + }, ); TableCellLink.displayName = 'TableCellLink'; diff --git a/packages/canon/src/components/Table/TableCellLink/types.ts b/packages/ui/src/components/Table/TableCellLink/types.ts similarity index 100% rename from packages/canon/src/components/Table/TableCellLink/types.ts rename to packages/ui/src/components/Table/TableCellLink/types.ts diff --git a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx similarity index 84% rename from packages/canon/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx rename to packages/ui/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx index 5ee482f4fc..230fc0e3d1 100644 --- a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx +++ b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.stories.tsx @@ -14,12 +14,20 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryFn, StoryObj } from '@storybook/react'; import { TableCellProfile } from './TableCellProfile'; +import { MemoryRouter } from 'react-router-dom'; const meta = { title: 'Components/Table/TableCellProfile', component: TableCellProfile, + decorators: [ + (Story: StoryFn) => ( + + + + ), + ], } satisfies Meta; export default meta; diff --git a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.styles.css b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.styles.css similarity index 71% rename from packages/canon/src/components/Table/TableCellProfile/TableCellProfile.styles.css rename to packages/ui/src/components/Table/TableCellProfile/TableCellProfile.styles.css index 30ab1fe683..4ec0f74899 100644 --- a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.styles.css +++ b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.styles.css @@ -14,14 +14,14 @@ * limitations under the License. */ -.canon-TableCellProfile { +.bui-TableCellProfile { display: flex; flex-direction: row; - gap: var(--canon-space-2); + gap: var(--bui-space-2); align-items: center; } -.canon-TableCellProfileAvatar { +.bui-TableCellProfileAvatar { display: inline-flex; justify-content: center; align-items: center; @@ -29,8 +29,8 @@ border-radius: 100%; user-select: none; font-weight: 500; - color: var(--canon-fg-primary); - background-color: var(--canon-bg-surface-2); + color: var(--bui-fg-primary); + background-color: var(--bui-bg-surface-2); font-size: 1rem; line-height: 1; overflow: hidden; @@ -38,20 +38,20 @@ width: 1.25rem; } -.canon-TableCellProfileAvatarImage { +.bui-TableCellProfileAvatarImage { object-fit: cover; height: 100%; width: 100%; } -.canon-TableCellProfileAvatarFallback { +.bui-TableCellProfileAvatarFallback { align-items: center; display: flex; justify-content: center; height: 100%; width: 100%; - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - box-shadow: inset 0 0 0 1px var(--canon-border); - border-radius: var(--canon-radius-full); + font-size: var(--bui-font-size-2); + font-weight: var(--bui-font-weight-regular); + box-shadow: inset 0 0 0 1px var(--bui-border); + border-radius: var(--bui-radius-full); } diff --git a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.tsx b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.tsx similarity index 52% rename from packages/canon/src/components/Table/TableCellProfile/TableCellProfile.tsx rename to packages/ui/src/components/Table/TableCellProfile/TableCellProfile.tsx index 78d82f59aa..bb2371bd6d 100644 --- a/packages/canon/src/components/Table/TableCellProfile/TableCellProfile.tsx +++ b/packages/ui/src/components/Table/TableCellProfile/TableCellProfile.tsx @@ -20,40 +20,45 @@ import { TableCellProfileProps } from './types'; import { Text } from '../../Text/Text'; import { Link } from '../../Link/Link'; import { Avatar } from '@base-ui-components/react/avatar'; +import { useStyles } from '../../../hooks/useStyles'; /** @public */ const TableCellProfile = forwardRef( - ({ className, src, name, to, withImage = true, ...rest }, ref) => ( -
- {withImage && ( - - - - {(name || '') - .split(' ') - .map(word => word[0]) - .join('') - .toLocaleUpperCase('en-US') - .slice(0, 1)} - - - )} - {name && to ? ( - {name} - ) : ( - {name} - )} -
- ), + ({ className, src, name, to, withImage = true, ...rest }, ref) => { + const { classNames } = useStyles('Table'); + + return ( +
+ {withImage && ( + + + + {(name || '') + .split(' ') + .map(word => word[0]) + .join('') + .toLocaleUpperCase('en-US') + .slice(0, 1)} + + + )} + {name && to ? ( + {name} + ) : ( + {name} + )} +
+ ); + }, ); TableCellProfile.displayName = 'TableCellProfile'; diff --git a/packages/canon/src/components/Table/TableCellProfile/types.ts b/packages/ui/src/components/Table/TableCellProfile/types.ts similarity index 100% rename from packages/canon/src/components/Table/TableCellProfile/types.ts rename to packages/ui/src/components/Table/TableCellProfile/types.ts diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx b/packages/ui/src/components/Table/TableCellText/TableCellText.stories.tsx similarity index 100% rename from packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx rename to packages/ui/src/components/Table/TableCellText/TableCellText.stories.tsx diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.styles.css b/packages/ui/src/components/Table/TableCellText/TableCellText.styles.css similarity index 92% rename from packages/canon/src/components/Table/TableCellText/TableCellText.styles.css rename to packages/ui/src/components/Table/TableCellText/TableCellText.styles.css index 7a645a1fcb..f38f8b3689 100644 --- a/packages/canon/src/components/Table/TableCellText/TableCellText.styles.css +++ b/packages/ui/src/components/Table/TableCellText/TableCellText.styles.css @@ -14,8 +14,8 @@ * limitations under the License. */ -.canon-TableCellText { +.bui-TableCellText { display: flex; flex-direction: column; - gap: var(--canon-space-0_5); + gap: var(--bui-space-0_5); } diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.tsx b/packages/ui/src/components/Table/TableCellText/TableCellText.tsx similarity index 64% rename from packages/canon/src/components/Table/TableCellText/TableCellText.tsx rename to packages/ui/src/components/Table/TableCellText/TableCellText.tsx index d5496d799b..ee8db20ada 100644 --- a/packages/canon/src/components/Table/TableCellText/TableCellText.tsx +++ b/packages/ui/src/components/Table/TableCellText/TableCellText.tsx @@ -18,23 +18,28 @@ import { forwardRef } from 'react'; import clsx from 'clsx'; import { TableCellTextProps } from './types'; import { Text } from '../../Text/Text'; +import { useStyles } from '../../../hooks/useStyles'; /** @public */ const TableCellText = forwardRef( - ({ className, title, description, ...props }, ref) => ( -
- {title && {title}} - {description && ( - - {description} - - )} -
- ), + ({ className, title, description, ...props }, ref) => { + const { classNames } = useStyles('Table'); + + return ( +
+ {title && {title}} + {description && ( + + {description} + + )} +
+ ); + }, ); TableCellText.displayName = 'TableCellText'; diff --git a/packages/canon/src/components/Table/TableCellText/types.ts b/packages/ui/src/components/Table/TableCellText/types.ts similarity index 100% rename from packages/canon/src/components/Table/TableCellText/types.ts rename to packages/ui/src/components/Table/TableCellText/types.ts diff --git a/packages/canon/src/components/Table/index.ts b/packages/ui/src/components/Table/index.ts similarity index 100% rename from packages/canon/src/components/Table/index.ts rename to packages/ui/src/components/Table/index.ts diff --git a/packages/ui/src/components/Table/styles.css b/packages/ui/src/components/Table/styles.css new file mode 100644 index 0000000000..63502eaa51 --- /dev/null +++ b/packages/ui/src/components/Table/styles.css @@ -0,0 +1,25 @@ +.bui-TableRoot { + width: 100%; + caption-side: bottom; + border-collapse: collapse; +} + +.bui-TableHead { + text-align: left; + padding: var(--bui-space-3); + font-size: var(--bui-font-size-3); + color: var(--bui-fg-primary); +} + +.bui-TableBody { + color: var(--bui-fg-primary); +} + +.bui-TableRow { + border-bottom: 1px solid var(--bui-border); + transition: color 0.2s ease-in-out; +} + +.bui-TableBody .bui-TableRow:hover { + background-color: var(--bui-gray-2); +} diff --git a/packages/ui/src/components/Tabs/Tabs.stories.tsx b/packages/ui/src/components/Tabs/Tabs.stories.tsx new file mode 100644 index 0000000000..9f6e05e289 --- /dev/null +++ b/packages/ui/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,455 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryFn, StoryObj } from '@storybook/react'; +import { Tabs, TabList, Tab, TabPanel } from './Tabs'; +import { MemoryRouter } from 'react-router-dom'; +import { Box } from '../Box'; +import { Text } from '../Text'; + +const meta = { + title: 'Components/Tabs', + component: Tabs, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const withRouter = (Story: StoryFn) => ( + + + +); + +export const Default: Story = { + args: { + children: '', + }, + decorators: [withRouter], + render: () => ( + + + Tab 1 + Tab 2 + Tab 3 With long title + + + ), +}; + +export const WithTabPanels: Story = { + args: { + children: '', + }, + decorators: [withRouter], + render: () => ( + + + Settings + Profile + Preferences + + + Settings panel content goes here + + + Profile panel content goes here + + + Preferences panel content goes here + + + ), +}; + +export const WithMockedURLTab2: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Tab 1 + + + Tab 2 + + + Tab 3 With long title + + + + + + Current URL is mocked to be: /tab2 + + + Notice how the "Tab 2" tab is selected (highlighted) because it + matches the current path. + + + + ), +}; + +export const WithMockedURLTab3: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Tab 1 + + + Tab 2 + + + Tab 3 With long title + + + + + + Current URL is mocked to be: /tab3 + + + Notice how the "Tab 3 With long title" tab is selected (highlighted) + because it matches the current path. + + + + ), +}; + +export const WithMockedURLNoMatch: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Tab 1 + + + Tab 2 + + + Tab 3 With long title + + + + + + Current URL is mocked to be: /some-other-page + + + No tab is selected because the current path doesn't match any tab's + href. + + + Tabs without href (like "Tab 1", "Tab 2", "Tab 3 With long title") + fall back to React Aria's internal state. + + + + ), +}; + +// New stories for testing match strategies + +export const ExactMatchingDefault: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Mentorship + + + Events + + + Catalog + + + + + + Current URL: /mentorship/events + + + Using default exact matching, only the "Events" tab is active because + it exactly matches the URL. + + + The "Mentorship" tab is NOT active even though the URL contains + "/mentorship". + + + + ), +}; + +export const PrefixMatchingForNestedRoutes: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Mentorship + + + Events + + + Catalog + + + + + + Current URL: /mentorship/events + + + The "Mentorship" tab uses prefix matching and IS active because + "/mentorship/events" starts with "/mentorship". + + + The "Events" tab uses exact matching and is also active because it + exactly matches. + + + The "Catalog" tab uses prefix matching but is NOT active because the + URL doesn't start with "/catalog". + + + + ), +}; + +export const PrefixMatchingDeepNesting: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Home + + + Catalog + + + Mentorship + + + + + + Current URL: /catalog/users/john/details + + + The "Catalog" tab is active because it uses prefix matching and the + URL starts with "/catalog". + + This works for any level of nesting under "/catalog". + + + ), +}; + +export const MixedMatchingStrategies: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Overview + + + Analytics + + + Settings + + + Help + + + + + + Current URL: /dashboard/analytics/reports + + + • "Overview" tab: exact matching, NOT active (doesn't exactly match + "/dashboard") + + + • "Analytics" tab: prefix matching, IS active (URL starts with + "/dashboard/analytics") + + + • "Settings" tab: prefix matching, NOT active (URL doesn't start with + "/dashboard/settings") + + + • "Help" tab: exact matching, NOT active (doesn't exactly match + "/help") + + + + ), +}; + +export const PrefixMatchingEdgeCases: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Foo + + + Foobar + + + Foo (exact) + + + + + + Current URL: /foobar + + + • "Foo" tab (prefix): NOT active - prevents "/foo" from matching + "/foobar" + + + • "Foobar" tab (exact): IS active - exactly matches "/foobar" + + + • "Foo (exact)" tab: NOT active - doesn't exactly match "/foobar" + + + This shows that prefix matching properly requires a "/" separator to + prevent false matches. + + + + ), +}; + +export const PrefixMatchingWithSlash: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Foo + + + Foobar + + + Bar + + + + + + Current URL: /foo/bar + + + • "Foo" tab (prefix): IS active - "/foo/bar" starts with "/foo/" + + + • "Foobar" tab (exact): NOT active - doesn't exactly match "/foobar" + + + • "Bar" tab (prefix): NOT active - "/foo/bar" doesn't start with + "/bar" + + + This demonstrates proper prefix matching with the "/" separator. + + + + ), +}; + +export const RootPathMatching: Story = { + args: { + children: '', + }, + render: () => ( + + + + + Home + + + Home (prefix) + + + Catalog + + + + + + Current URL: / + + • "Home" tab (exact): IS active - exactly matches "/" + • "Home (prefix)" tab: IS active - "/" matches "/" + + • "Catalog" tab (prefix): NOT active - "/" doesn't start with + "/catalog" + + + + ), +}; diff --git a/packages/ui/src/components/Tabs/Tabs.styles.css b/packages/ui/src/components/Tabs/Tabs.styles.css new file mode 100644 index 0000000000..819fe458ed --- /dev/null +++ b/packages/ui/src/components/Tabs/Tabs.styles.css @@ -0,0 +1,82 @@ +.bui-Tabs { + /* Initialize CSS variables */ + --active-tab-left: 0px; + --active-tab-right: 0px; + --active-tab-top: 0px; + --active-tab-bottom: 0px; + --active-tab-width: 0px; + --active-tab-height: 0px; + --active-transition-duration: 0s; + + --hovered-tab-left: 0px; + --hovered-tab-right: 0px; + --hovered-tab-top: 0px; + --hovered-tab-bottom: 0px; + --hovered-tab-width: 0px; + --hovered-tab-height: 0px; + --hovered-tab-opacity: 0; + --hovered-transition-duration: 0s; +} + +.bui-TabList { + display: flex; + flex-direction: row; +} + +.bui-TabListWrapper { + position: relative; +} + +.bui-Tab { + font-size: var(--bui-font-size-3); + font-family: var(--bui-font-regular); + font-weight: var(--bui-font-weight-regular); + color: var(--bui-fg-secondary); + height: 36px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + position: relative; + z-index: 2; + padding-inline: var(--bui-space-2); + + &[data-selected='true'] { + color: var(--bui-fg-primary); + } +} + +.bui-TabActive { + content: ''; + position: absolute; + left: calc(var(--active-tab-left) + var(--bui-space-2)); + bottom: -1px; + width: calc(var(--active-tab-width) - var(--bui-space-4)); + height: 1px; + background-color: var(--bui-fg-primary); + border-radius: 4px; + transition: left var(--active-transition-duration) ease-out, + opacity 0.15s ease-out, width var(--active-transition-duration) ease-out; + opacity: 1; +} + +.bui-TabHovered { + content: ''; + position: absolute; + left: var(--hovered-tab-left); + top: calc(var(--hovered-tab-top) + 4px); + width: var(--hovered-tab-width); + height: calc(var(--hovered-tab-height) - 8px); + background-color: var(--bui-gray-2); + border-radius: 4px; + opacity: var(--hovered-tab-opacity); + transition: left var(--hovered-transition-duration) ease-out, + top var(--hovered-transition-duration) ease-out, + width var(--hovered-transition-duration) ease-out, + height var(--hovered-transition-duration) ease-out, opacity 0.15s ease-out; +} + +.bui-TabPanel { + padding-inline: var(--bui-space-2); + padding-top: var(--bui-space-4); +} diff --git a/packages/ui/src/components/Tabs/Tabs.tsx b/packages/ui/src/components/Tabs/Tabs.tsx new file mode 100644 index 0000000000..d4c820e529 --- /dev/null +++ b/packages/ui/src/components/Tabs/Tabs.tsx @@ -0,0 +1,233 @@ +/* + * Copyright 2024 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 { + useRef, + useState, + Children, + cloneElement, + isValidElement, + ReactNode, + createContext, + useContext, +} from 'react'; +import type { + TabsProps, + TabListProps, + TabPanelProps, + TabsContextValue, + TabProps, +} from './types'; +import { useLocation, useNavigate, useHref } from 'react-router-dom'; +import { TabsIndicators } from './TabsIndicators'; +import { + Tabs as AriaTabs, + TabList as AriaTabList, + Tab as AriaTab, + TabPanel as AriaTabPanel, + RouterProvider, + TabProps as AriaTabProps, +} from 'react-aria-components'; + +import { useStyles } from '../../hooks/useStyles'; + +const TabsContext = createContext(undefined); + +const useTabsContext = () => { + const context = useContext(TabsContext); + if (!context) { + throw new Error('Tab components must be used within a Tabs component'); + } + return context; +}; + +/** + * Utility function to determine if a tab should be active based on the matching strategy. + * This follows the pattern used in WorkaroundNavLink from the sidebar. + */ +const isTabActive = ( + tabHref: string, + currentPathname: string, + matchStrategy: 'exact' | 'prefix', +): boolean => { + if (matchStrategy === 'exact') { + return tabHref === currentPathname; + } + + // Prefix matching - similar to WorkaroundNavLink behavior + if (tabHref === currentPathname) { + return true; + } + + // Check if current path starts with tab href followed by a slash + // This prevents /foo matching /foobar + return currentPathname.startsWith(`${tabHref}/`); +}; + +/** + * A component that renders a list of tabs. + * + * @public + */ +export const Tabs = (props: TabsProps) => { + const { children, ...rest } = props; + const { classNames } = useStyles('Tabs'); + const tabsRef = useRef(null); + const tabRefs = useRef>(new Map()); + const [hoveredKey, setHoveredKey] = useState(null); + const prevHoveredKey = useRef(null); + let navigate = useNavigate(); + const location = useLocation(); + + const setTabRef = (key: string, element: HTMLDivElement | null) => { + if (element) { + tabRefs.current.set(key, element); + } else { + tabRefs.current.delete(key); + } + }; + + // If selectedKey is not provided, try to determine it from the current route + const computedSelectedKey = (() => { + const childrenArray = Children.toArray(children as ReactNode); + for (const child of childrenArray) { + if (isValidElement(child) && child.type === TabList) { + const tabListChildren = Children.toArray(child.props.children); + for (const tabChild of tabListChildren) { + if (isValidElement(tabChild) && tabChild.props.href) { + // Use tab-specific strategy, defaulting to 'exact' + const strategy = tabChild.props.matchStrategy || 'exact'; + if (isTabActive(tabChild.props.href, location.pathname, strategy)) { + return tabChild.props.id; + } + } + } + } + } + return undefined; + })(); + + if (!children) return null; + + const contextValue: TabsContextValue = { + tabsRef, + tabRefs, + hoveredKey, + prevHoveredKey, + setHoveredKey, + setTabRef, + }; + + return ( + + + + {children as ReactNode} + + + + ); +}; + +/** + * A component that renders a list of tabs. + * + * @public + */ +export const TabList = (props: TabListProps) => { + const { children, ...rest } = props; + const { classNames } = useStyles('Tabs'); + const { setHoveredKey, tabRefs, tabsRef, hoveredKey, prevHoveredKey } = + useTabsContext(); + + const handleHover = (key: string | null) => { + setHoveredKey(key); + }; + + // Clone children with additional props for hover and ref management + const enhancedChildren = Children.map(children as ReactNode, child => { + if (isValidElement(child)) { + return cloneElement(child, { + onHoverStart: () => handleHover(child.props.id as string), + onHoverEnd: () => handleHover(null), + } as Partial); + } + return child; + }); + + return ( +
+ + {enhancedChildren} + + +
+ ); +}; + +/** + * A component that renders a tab. + * + * @public + */ +export const Tab = (props: TabProps) => { + const { href, children, id, matchStrategy: _matchStrategy, ...rest } = props; + const { classNames } = useStyles('Tabs'); + const { setTabRef } = useTabsContext(); + + return ( + setTabRef(id as string, el as HTMLDivElement)} + href={href} + {...rest} + > + {children} + + ); +}; + +/** + * A component that renders the content of a tab. + * + * @public + */ +export const TabPanel = (props: TabPanelProps) => { + const { children, ...rest } = props; + const { classNames } = useStyles('Tabs'); + + return ( + + {children} + + ); +}; diff --git a/packages/ui/src/components/Tabs/TabsIndicators.tsx b/packages/ui/src/components/Tabs/TabsIndicators.tsx new file mode 100644 index 0000000000..fa2e29300d --- /dev/null +++ b/packages/ui/src/components/Tabs/TabsIndicators.tsx @@ -0,0 +1,191 @@ +/* + * Copyright 2024 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 { TabListStateContext } from 'react-aria-components'; +import { useStyles } from '../../hooks/useStyles'; +import { useContext, useEffect, useCallback, useRef } from 'react'; +import type { TabsIndicatorsProps } from './types'; + +/** + * A component that renders the indicators for the toolbar. + * + * @internal + */ +export const TabsIndicators = (props: TabsIndicatorsProps) => { + const { tabRefs, tabsRef, hoveredKey, prevHoveredKey } = props; + const { classNames } = useStyles('Tabs'); + const state = useContext(TabListStateContext); + const prevSelectedKey = useRef(null); + + const updateCSSVariables = useCallback(() => { + if (!tabsRef.current) return; + + const tabsRect = tabsRef.current.getBoundingClientRect(); + + // Set active tab variables + if (state?.selectedKey) { + const activeTab = tabRefs.current.get(state.selectedKey.toString()); + + if (activeTab) { + const activeRect = activeTab.getBoundingClientRect(); + const relativeLeft = activeRect.left - tabsRect.left; + const relativeTop = activeRect.top - tabsRect.top; + + // Control transition timing based on whether this is the first time setting active tab + const isFirstActiveTab = prevSelectedKey.current === null; + + if (isFirstActiveTab) { + // First time setting active tab: no transitions for position + tabsRef.current.style.setProperty( + '--active-transition-duration', + '0s', + ); + // Enable transitions on next frame for future tab switches + requestAnimationFrame(() => { + if (tabsRef.current) { + tabsRef.current.style.setProperty( + '--active-transition-duration', + '0.25s', + ); + } + }); + } else { + // Switching between tabs: full transitions + tabsRef.current.style.setProperty( + '--active-transition-duration', + '0.25s', + ); + } + + // Update previous selected key for next time + prevSelectedKey.current = state.selectedKey.toString(); + + tabsRef.current.style.setProperty( + '--active-tab-left', + `${relativeLeft}px`, + ); + tabsRef.current.style.setProperty( + '--active-tab-right', + `${relativeLeft + activeRect.width}px`, + ); + tabsRef.current.style.setProperty( + '--active-tab-top', + `${relativeTop}px`, + ); + tabsRef.current.style.setProperty( + '--active-tab-bottom', + `${relativeTop + activeRect.height}px`, + ); + tabsRef.current.style.setProperty( + '--active-tab-width', + `${activeRect.width}px`, + ); + tabsRef.current.style.setProperty( + '--active-tab-height', + `${activeRect.height}px`, + ); + } + } + + // Set hovered tab variables + if (hoveredKey) { + const hoveredTab = tabRefs.current.get(hoveredKey); + if (hoveredTab) { + const hoveredRect = hoveredTab.getBoundingClientRect(); + const relativeLeft = hoveredRect.left - tabsRect.left; + const relativeTop = hoveredRect.top - tabsRect.top; + + tabsRef.current.style.setProperty( + '--hovered-tab-left', + `${relativeLeft}px`, + ); + tabsRef.current.style.setProperty( + '--hovered-tab-right', + `${relativeLeft + hoveredRect.width}px`, + ); + tabsRef.current.style.setProperty( + '--hovered-tab-top', + `${relativeTop}px`, + ); + tabsRef.current.style.setProperty( + '--hovered-tab-bottom', + `${relativeTop + hoveredRect.height}px`, + ); + tabsRef.current.style.setProperty( + '--hovered-tab-width', + `${hoveredRect.width}px`, + ); + tabsRef.current.style.setProperty( + '--hovered-tab-height', + `${hoveredRect.height}px`, + ); + // Control transition timing based on whether this is a new hover session + const isNewHoverSession = prevHoveredKey.current === null; + + if (isNewHoverSession) { + // Starting new hover session: no transitions for position + tabsRef.current.style.setProperty( + '--hovered-transition-duration', + '0s', + ); + // Enable transitions on next frame for future tab switches + requestAnimationFrame(() => { + if (tabsRef.current) { + tabsRef.current.style.setProperty( + '--hovered-transition-duration', + '0.2s', + ); + } + }); + } else { + // Moving between tabs in same session: full transitions + tabsRef.current.style.setProperty( + '--hovered-transition-duration', + '0.2s', + ); + } + + // Update previous hover key for next time + prevHoveredKey.current = hoveredKey; + + tabsRef.current.style.setProperty('--hovered-tab-opacity', '1'); + } + } else { + // When not hovering, hide with opacity and reset for next hover session + tabsRef.current.style.setProperty('--hovered-tab-opacity', '0'); + + // Reset previous hover key so next hover is treated as new session + prevHoveredKey.current = null; + } + }, [state?.selectedKey, hoveredKey, tabRefs.current]); + + useEffect(() => { + updateCSSVariables(); + }, [updateCSSVariables, tabRefs.current.size]); + + useEffect(() => { + const handleResize = () => updateCSSVariables(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, [updateCSSVariables]); + + return ( + <> +
+
+ + ); +}; diff --git a/packages/canon/src/components/Tabs/index.ts b/packages/ui/src/components/Tabs/index.ts similarity index 78% rename from packages/canon/src/components/Tabs/index.ts rename to packages/ui/src/components/Tabs/index.ts index ba6ca91de7..38a6f20ea7 100644 --- a/packages/canon/src/components/Tabs/index.ts +++ b/packages/ui/src/components/Tabs/index.ts @@ -14,5 +14,11 @@ * limitations under the License. */ -export { Tabs } from './Tabs'; -export type { TabsRootWithoutOrientation } from './types'; +export { Tabs, TabList, Tab, TabPanel } from './Tabs'; +export type { + TabsProps, + TabListProps, + TabPanelProps, + TabProps, + TabMatchStrategy, +} from './types'; diff --git a/packages/ui/src/components/Tabs/types.ts b/packages/ui/src/components/Tabs/types.ts new file mode 100644 index 0000000000..05d080441b --- /dev/null +++ b/packages/ui/src/components/Tabs/types.ts @@ -0,0 +1,90 @@ +/* + * 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 type { + TabsProps as AriaTabsProps, + TabListProps as AriaTabListProps, + TabPanelProps as AriaTabPanelProps, + TabProps as AriaTabProps, +} from 'react-aria-components'; +import { MutableRefObject } from 'react'; + +/** + * Strategies for matching the current route to determine which tab should be active. + * + * @public + */ +export type TabMatchStrategy = 'exact' | 'prefix'; + +/** + * Props for the Tabs component. + * + * @public + */ +export interface TabsProps extends AriaTabsProps {} + +/** + * Props for the TabList component. + * + * @public + */ +export interface TabListProps extends Omit, 'items'> {} + +/** + * Props for the Tab component. + * + * @public + */ +export interface TabProps extends AriaTabProps { + /** + * Strategy for matching the current route to determine if this tab should be active. + * - 'exact': Tab href must exactly match the current pathname (default) + * - 'prefix': Tab is active if current pathname starts with tab href + */ + matchStrategy?: 'exact' | 'prefix'; +} + +/** Context for sharing refs between Tabs and TabList + * + * @internal + */ +export interface TabsContextValue { + tabsRef: React.RefObject; + tabRefs: React.MutableRefObject>; + hoveredKey: string | null; + prevHoveredKey: React.MutableRefObject; + setHoveredKey: (key: string | null) => void; + setTabRef: (key: string, element: HTMLDivElement | null) => void; +} + +/** + * Props for the TabPanel component. + * + * @public + */ +export interface TabPanelProps extends AriaTabPanelProps {} + +/** + * Props for the TabsIndicators component. + * + * @internal + */ +export interface TabsIndicatorsProps { + tabRefs: MutableRefObject>; + tabsRef: MutableRefObject; + hoveredKey: string | null; + prevHoveredKey: MutableRefObject; +} diff --git a/packages/canon/src/components/Text/Text.stories.tsx b/packages/ui/src/components/Text/Text.stories.tsx similarity index 51% rename from packages/canon/src/components/Text/Text.stories.tsx rename to packages/ui/src/components/Text/Text.stories.tsx index 5bb918f52e..562b4bb607 100644 --- a/packages/canon/src/components/Text/Text.stories.tsx +++ b/packages/ui/src/components/Text/Text.stories.tsx @@ -33,7 +33,6 @@ export const Default: 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?", - style: { maxWidth: '600px' }, }, }; @@ -42,23 +41,54 @@ export const AllVariants: Story = { ...Default.args, }, render: args => ( - - - - - + + + + + + + + + ), }; export const AllWeights: Story = { - args: { - ...Default.args, - }, - render: args => ( + render: () => ( - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), }; @@ -69,11 +99,11 @@ export const AllColors: Story = { }, render: args => ( - - - - - + + + + + ), }; @@ -82,6 +112,8 @@ export const Truncate: Story = { args: { ...Default.args, truncate: true, + as: 'p', + style: { width: '480px' }, }, }; @@ -89,8 +121,8 @@ export const Responsive: Story = { args: { ...Default.args, variant: { - xs: 'label', - md: 'body', + xs: 'title-x-small', + md: 'body-large', }, }, }; @@ -111,7 +143,7 @@ export const WrappedInLink: Story = { export const CustomRender: Story = { args: { ...Default.args, - as: 'span', + as: 'label', }, }; @@ -119,25 +151,25 @@ export const Playground: Story = { render: () => ( Subtitle - + 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? Body - + 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? Caption - + 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? Label - + 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? diff --git a/packages/canon/src/components/Text/Text.tsx b/packages/ui/src/components/Text/Text.tsx similarity index 59% rename from packages/canon/src/components/Text/Text.tsx rename to packages/ui/src/components/Text/Text.tsx index abf03ef0bd..533baa6067 100644 --- a/packages/canon/src/components/Text/Text.tsx +++ b/packages/ui/src/components/Text/Text.tsx @@ -15,15 +15,15 @@ */ import { forwardRef } from 'react'; -import { useResponsiveValue } from '../../hooks/useResponsiveValue'; import clsx from 'clsx'; import type { ElementType } from 'react'; import type { TextProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; -function TextComponent( +function TextComponent( { as, - variant = 'body', + variant = 'body-medium', weight = 'regular', color = 'primary', className, @@ -33,21 +33,21 @@ function TextComponent( }: TextProps, ref: React.Ref, ) { - const Component = as || 'p'; + const Component = as || 'span'; - // Get the responsive values for the variant and weight - const responsiveVariant = useResponsiveValue(variant); - const responsiveWeight = useResponsiveValue(weight); - const responsiveColor = useResponsiveValue(color); + const { classNames, dataAttributes } = useStyles('Text', { + variant, + weight, + color, + }); return ( @@ -57,8 +57,11 @@ function TextComponent( TextComponent.displayName = 'Text'; /** @public */ -export const Text = forwardRef(TextComponent) as ( - props: TextProps & { ref?: React.Ref }, -) => React.ReactElement | null; +export const Text = forwardRef(TextComponent) as { + ( + props: TextProps & { ref?: React.ComponentPropsWithRef['ref'] }, + ): React.ReactElement, T>; + displayName: string; +}; -(Text as any).displayName = 'Text'; +Text.displayName = 'Text'; diff --git a/packages/canon/src/components/Text/index.ts b/packages/ui/src/components/Text/index.ts similarity index 100% rename from packages/canon/src/components/Text/index.ts rename to packages/ui/src/components/Text/index.ts diff --git a/packages/ui/src/components/Text/styles.css b/packages/ui/src/components/Text/styles.css new file mode 100644 index 0000000000..562d2a5356 --- /dev/null +++ b/packages/ui/src/components/Text/styles.css @@ -0,0 +1,103 @@ +/* + * Copyright 2024 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. + */ + +.bui-Text { + font-family: var(--bui-font-regular); + padding: 0; + margin: 0; +} + +.bui-Text[data-variant='title-large'] { + font-size: var(--bui-font-size-8); + line-height: 140%; +} + +.bui-Text[data-variant='title-medium'] { + font-size: var(--bui-font-size-7); + line-height: 140%; +} + +.bui-Text[data-variant='title-small'] { + font-size: var(--bui-font-size-6); + line-height: 140%; +} + +.bui-Text[data-variant='title-x-small'] { + font-size: var(--bui-font-size-5); + line-height: 140%; +} + +.bui-Text[data-variant='body-large'] { + font-size: var(--bui-font-size-4); + line-height: 140%; +} + +.bui-Text[data-variant='body-medium'] { + font-size: var(--bui-font-size-3); + line-height: 140%; +} + +.bui-Text[data-variant='body-small'] { + font-size: var(--bui-font-size-2); + line-height: 140%; +} + +.bui-Text[data-variant='body-x-small'] { + font-size: var(--bui-font-size-1); + line-height: 140%; +} + +.bui-Text[data-weight='regular'] { + font-weight: var(--bui-font-weight-regular); +} + +.bui-Text[data-weight='bold'] { + font-weight: var(--bui-font-weight-bold); +} + +.bui-Text[data-color='primary'] { + color: var(--bui-fg-primary); +} + +.bui-Text[data-color='secondary'] { + color: var(--bui-fg-secondary); +} + +.bui-Text[data-color='danger'] { + color: var(--bui-fg-danger); +} + +.bui-Text[data-color='warning'] { + color: var(--bui-fg-warning); +} + +.bui-Text[data-color='success'] { + color: var(--bui-fg-success); +} + +.bui-Text[data-truncate] { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bui-Text[data-as='span'], +.bui-Text[data-as='label'], +.bui-Text[data-as='strong'], +.bui-Text[data-as='em'], +.bui-Text[data-as='small'] { + display: inline-block; +} diff --git a/packages/canon/src/components/Text/types.ts b/packages/ui/src/components/Text/types.ts similarity index 56% rename from packages/canon/src/components/Text/types.ts rename to packages/ui/src/components/Text/types.ts index ed01956248..e0b0e4aa32 100644 --- a/packages/canon/src/components/Text/types.ts +++ b/packages/ui/src/components/Text/types.ts @@ -15,35 +15,40 @@ */ import type { ElementType, ComponentPropsWithRef } from 'react'; -import type { Breakpoint } from '../../types'; +import type { + Breakpoint, + TextVariants, + TextWeights, + TextColors, + TextColorStatus, +} from '../../types'; /** @public */ export type TextOwnProps = { - as?: 'p' | 'span' | 'label'; - variant?: - | 'subtitle' - | 'body' - | 'caption' + as?: + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h5' + | 'h6' + | 'p' + | 'span' | 'label' - | Partial>; - weight?: 'regular' | 'bold' | Partial>; + | 'div' + | 'strong' + | 'em' + | 'small' + | 'legend'; + variant?: TextVariants | Partial>; + weight?: TextWeights | Partial>; color?: - | 'primary' - | 'secondary' - | 'danger' - | 'warning' - | 'success' - | Partial< - Record< - Breakpoint, - 'primary' | 'secondary' | 'danger' | 'warning' | 'success' - > - >; + | TextColors + | TextColorStatus + | Partial>; truncate?: boolean; - className?: string; - style?: React.CSSProperties; }; /** @public */ -export type TextProps = TextOwnProps & +export type TextProps = TextOwnProps & Omit, keyof TextOwnProps>; diff --git a/packages/canon/src/components/TextField/TextField.stories.tsx b/packages/ui/src/components/TextField/TextField.stories.tsx similarity index 95% rename from packages/canon/src/components/TextField/TextField.stories.tsx rename to packages/ui/src/components/TextField/TextField.stories.tsx index 157590ae11..7adc84e909 100644 --- a/packages/canon/src/components/TextField/TextField.stories.tsx +++ b/packages/ui/src/components/TextField/TextField.stories.tsx @@ -97,9 +97,15 @@ export const Disabled: Story = { export const WithIcon: Story = { args: { ...Default.args, - placeholder: 'Search...', - icon: , }, + render: args => ( + } + /> + ), }; export const DisabledWithIcon: Story = { diff --git a/packages/ui/src/components/TextField/TextField.styles.css b/packages/ui/src/components/TextField/TextField.styles.css new file mode 100644 index 0000000000..abdce20294 --- /dev/null +++ b/packages/ui/src/components/TextField/TextField.styles.css @@ -0,0 +1,114 @@ +/* + * Copyright 2024 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. + */ + +.bui-TextField { + display: flex; + flex-direction: column; + font-family: var(--bui-font-regular); + width: 100%; +} + +.bui-InputWrapper { + position: relative; + + &[data-size='small'] .bui-Input { + height: 2rem; + } + + &[data-size='medium'] .bui-Input { + height: 2.5rem; + } + + &[data-size='small'] .bui-Input[data-icon] { + padding-left: var(--bui-space-8); + } + + &[data-size='medium'] .bui-Input[data-icon] { + padding-left: var(--bui-space-9); + } +} + +.bui-InputIcon { + position: absolute; + left: var(--bui-space-3); + top: 50%; + transform: translateY(-50%); + margin-right: var(--bui-space-1); + color: var(--bui-fg-primary); + flex-shrink: 0; + + &[data-size='small'], + &[data-size='small'] svg { + width: 1rem; + height: 1rem; + } + + &[data-size='medium'], + &[data-size='medium'] svg { + width: 1.25rem; + height: 1.25rem; + } +} + +.bui-Input { + display: flex; + align-items: center; + padding: 0 var(--bui-space-3); + border-radius: var(--bui-radius-3); + border: 1px solid var(--bui-border); + background-color: var(--bui-bg-surface-1); + font-size: var(--bui-font-size-3); + font-family: var(--bui-font-regular); + font-weight: var(--bui-font-weight-regular); + color: var(--bui-fg-primary); + transition: border-color 0.2s ease-in-out, outline-color 0.2s ease-in-out; + width: 100%; + height: 100%; + cursor: inherit; + + &::-webkit-search-cancel-button, + &::-webkit-search-decoration { + -webkit-appearance: none; + } + + &::placeholder { + color: var(--bui-fg-secondary); + } + + &[data-focused] { + outline-color: var(--bui-border-pressed); + outline-width: 0px; + } + + &[data-hovered] { + border-color: var(--bui-border-hover); + } + + &[data-focused] { + border-color: var(--bui-border-pressed); + outline-width: 0px; + } + + &[data-invalid] { + border-color: var(--bui-fg-danger); + } + + &[data-disabled] { + opacity: 0.5; + cursor: not-allowed; + border: 1px solid var(--bui-border-disabled); + } +} diff --git a/packages/canon/src/components/TextField/TextField.tsx b/packages/ui/src/components/TextField/TextField.tsx similarity index 83% rename from packages/canon/src/components/TextField/TextField.tsx rename to packages/ui/src/components/TextField/TextField.tsx index 8c8471b0ef..2756c3c85f 100644 --- a/packages/canon/src/components/TextField/TextField.tsx +++ b/packages/ui/src/components/TextField/TextField.tsx @@ -16,12 +16,12 @@ import { forwardRef, useEffect } from 'react'; import { Input, TextField as AriaTextField } from 'react-aria-components'; -import { useResponsiveValue } from '../../hooks/useResponsiveValue'; import clsx from 'clsx'; import { FieldLabel } from '../FieldLabel'; import { FieldError } from '../FieldError'; import type { TextFieldProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; /** @public */ export const TextField = forwardRef( @@ -48,8 +48,9 @@ export const TextField = forwardRef( } }, [label, ariaLabel, ariaLabelledBy]); - // Get the responsive value for the variant - const responsiveSize = useResponsiveValue(size); + const { classNames, dataAttributes } = useStyles('TextField', { + size, + }); // If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required. const secondaryLabelText = @@ -57,8 +58,8 @@ export const TextField = forwardRef( return ( ( secondaryLabel={secondaryLabelText} description={description} /> -
+
{icon && ( )} diff --git a/packages/canon/src/components/TextField/index.ts b/packages/ui/src/components/TextField/index.ts similarity index 100% rename from packages/canon/src/components/TextField/index.ts rename to packages/ui/src/components/TextField/index.ts diff --git a/packages/canon/src/components/TextField/types.ts b/packages/ui/src/components/TextField/types.ts similarity index 100% rename from packages/canon/src/components/TextField/types.ts rename to packages/ui/src/components/TextField/types.ts diff --git a/packages/ui/src/components/Tooltip/Tooltip.stories.tsx b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx new file mode 100644 index 0000000000..0154e21800 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx @@ -0,0 +1,125 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj } from '@storybook/react'; +import { Placement } from '@react-types/overlays'; +import { TooltipTrigger, Tooltip } from './Tooltip'; +import { Button } from '../Button/Button'; + +const meta = { + title: 'Components/Tooltip', + component: TooltipTrigger, + parameters: { layout: 'centered' }, + argTypes: { + isOpen: { + control: { type: 'boolean' }, + }, + isDisabled: { + control: { type: 'boolean' }, + }, + placement: { + options: ['top', 'right', 'bottom', 'left'], + control: { type: 'inline-radio' }, + }, + delay: { + control: { type: 'number' }, + }, + closeDelay: { + control: { type: 'number' }, + }, + }, + render: ({ tooltip, isOpen, isDisabled, placement, delay, closeDelay }) => ( + + + {tooltip ?? 'I am a tooltip'} + + ), +} as Meta<{ + tooltip?: string; + isOpen?: boolean; + isDisabled?: boolean; + placement?: Placement; + delay?: number; + closeDelay?: number; +}>; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + tooltip: 'I am a tooltip', + }, +}; + +export const IsOpen: Story = { + args: { + ...Default.args, + isOpen: true, + }, +}; + +export const IsDisabled: Story = { + args: { + ...Default.args, + isDisabled: true, + }, +}; + +export const NoDelays: Story = { + args: { + ...Default.args, + delay: 0, + closeDelay: 0, + }, +}; + +export const OrthogonalPlacements: Story = { + parameters: { + controls: { + exclude: ['placement'], + }, + }, + args: { + ...Default.args, + isOpen: true, + }, + render: ({ isOpen, tooltip }) => { + return ( + + + {tooltip} + {tooltip} + {tooltip} + {tooltip} + + ); + }, +}; + +export const WithLongText: Story = { + args: { + ...Default.args, + isOpen: true, + tooltip: + '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/Tooltip/Tooltip.styles.css b/packages/ui/src/components/Tooltip/Tooltip.styles.css new file mode 100644 index 0000000000..f80a12bbc1 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.styles.css @@ -0,0 +1,123 @@ +/* + * Copyright 2024 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. + */ + +.bui-Tooltip { + box-shadow: 0 10px 15px -3px rgba(0 0 0 / 0.1), + 0 4px 6px -4px rgba(0 0 0 / 0.1); + border-radius: 4px; + background: var(--bui-bg-surface-1); + border: 1px solid var(--bui-gray-3); + forced-color-adjust: none; + outline: none; + padding: var(--bui-space-2) var(--bui-space-3); + max-width: 240px; + /* fixes FF gap */ + transform: translate3d(0, 0, 0); + transition: transform 200ms, opacity 200ms; + font-size: var(--bui-font-size-3); + font-family: var(--bui-font-regular); + color: var(--bui-fg-primary); + + &[data-entering], + &[data-exiting] { + transform: var(--origin); + opacity: 0; + } + + --tooltip-offset: var(--bui-space-3); + + &[data-placement='top'] { + margin-bottom: var(--tooltip-offset); + --origin: translateY(4px); + } + + &[data-placement='right'] { + margin-left: var(--tooltip-offset); + --origin: translateX(-4px); + } + + &[data-placement='bottom'] { + margin-top: var(--tooltip-offset); + --origin: translateY(-4px); + } + + &[data-placement='left'] { + margin-right: var(--tooltip-offset); + --origin: translateX(4px); + } +} + +.bui-TooltipArrow { + & svg { + display: block; + + /* The tooltip is rendered overlaying the main + tooltip element by 1px. This causes the borders + to overlap, which causes minor visual artifacts + with transparent border colors. To mitigate this, + we split the stroke and fill across separate + elements in order to guarantee that the stroke is + always overlaying a consistent color. */ + path:nth-child(1) { + fill: var(--bui-bg-surface-1); + } + + path:nth-child(2) { + fill: var(--bui-gray-3); + } + + /* The arrow svg overlaps the tooltip by 2px, so we + need to adjust the margins accordingly. */ + --tooltip-arrow-overlap: -2px; + } + + &[data-placement='top'] svg { + margin-top: var(--tooltip-arrow-overlap); + } + + &[data-placement='bottom'] svg { + margin-bottom: var(--tooltip-arrow-overlap); + transform: rotate(180deg); + } + + &[data-placement='right'] svg { + margin-right: var(--tooltip-arrow-overlap); + transform: rotate(90deg); + } + + &[data-placement='left'] svg { + margin-left: var(--tooltip-arrow-overlap); + transform: rotate(-90deg); + } +} + +[data-theme='dark'] { + .bui-Tooltip { + background: var(--bui-bg-surface-2); + box-shadow: none; + border: 1px solid var(--bui-gray-4); + } + + .bui-TooltipArrow { + svg path:nth-child(1) { + fill: var(--bui-bg-surface-2); + } + + svg path:nth-child(2) { + fill: var(--bui-gray-4); + } + } +} diff --git a/packages/ui/src/components/Tooltip/Tooltip.tsx b/packages/ui/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 0000000000..4503a1ce90 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2024 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 { forwardRef } from 'react'; +import { + OverlayArrow, + Tooltip as AriaTooltip, + TooltipTrigger as AriaTooltipTrigger, + TooltipTriggerComponentProps, +} from 'react-aria-components'; +import clsx from 'clsx'; +import { TooltipProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; + +/** @public */ +export const TooltipTrigger = (props: TooltipTriggerComponentProps) => { + const { delay = 600 } = props; + + return ; +}; + +/** @public */ +export const Tooltip = forwardRef( + ({ className, children, ...rest }, ref) => { + const { classNames } = useStyles('Tooltip'); + + return ( + + + + + + + + {children} + + ); + }, +); + +Tooltip.displayName = 'Tooltip'; diff --git a/packages/ui/src/components/Tooltip/index.ts b/packages/ui/src/components/Tooltip/index.ts new file mode 100644 index 0000000000..613631091b --- /dev/null +++ b/packages/ui/src/components/Tooltip/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2024 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 { TooltipTrigger, Tooltip } from './Tooltip'; +export type { TooltipProps } from './types'; diff --git a/packages/ui/src/components/Tooltip/types.ts b/packages/ui/src/components/Tooltip/types.ts new file mode 100644 index 0000000000..2ef44fbbf4 --- /dev/null +++ b/packages/ui/src/components/Tooltip/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2024 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 { TooltipProps as AriaTooltipProps } from 'react-aria-components'; + +/** @public */ +export interface TooltipProps extends Omit { + children: React.ReactNode; +} diff --git a/packages/canon/src/css/components.css b/packages/ui/src/css/components.css similarity index 86% rename from packages/canon/src/css/components.css rename to packages/ui/src/css/components.css index 407723fcc9..268bbe40dd 100644 --- a/packages/canon/src/css/components.css +++ b/packages/ui/src/css/components.css @@ -18,6 +18,7 @@ @import '../components/Box/styles.css'; @import '../components/Button/styles.css'; @import '../components/ButtonIcon/styles.css'; +@import '../components/Card/Card.styles.css'; @import '../components/Checkbox/styles.css'; @import '../components/Collapsible/Collapsible.styles.css'; @import '../components/Container/styles.css'; @@ -27,10 +28,12 @@ @import '../components/FieldLabel/FieldLabel.styles.css'; @import '../components/Flex/styles.css'; @import '../components/Grid/styles.css'; -@import '../components/Heading/styles.css'; +@import '../components/Header/Header.styles.css'; +@import '../components/HeaderPage/HeaderPage.styles.css'; @import '../components/Icon/styles.css'; @import '../components/Link/styles.css'; @import '../components/Menu/Menu.styles.css'; +@import '../components/Popover/Popover.styles.css'; @import '../components/RadioGroup/RadioGroup.styles.css'; @import '../components/Table/styles.css'; @import '../components/Table/TableCell/TableCell.styles.css'; @@ -40,6 +43,8 @@ @import '../components/Tabs/Tabs.styles.css'; @import '../components/Text/styles.css'; @import '../components/TextField/TextField.styles.css'; +@import '../components/SearchField/SearchField.styles.css'; +@import '../components/Skeleton/Skeleton.styles.css'; @import '../components/Tooltip/Tooltip.styles.css'; @import '../components/ScrollArea/ScrollArea.styles.css'; @import '../components/Select/Select.styles.css'; diff --git a/packages/ui/src/css/core.css b/packages/ui/src/css/core.css new file mode 100644 index 0000000000..e74e606acd --- /dev/null +++ b/packages/ui/src/css/core.css @@ -0,0 +1,200 @@ +/* + * Copyright 2024 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. + */ + +/* Normalize */ +@import './normalize.css'; +@import './utilities.css'; + +/* Global reset */ +:where(a) { + color: inherit; + text-decoration: none; +} + +@keyframes pulse { + 50% { + opacity: 0.5; + } +} + +/* Light theme tokens */ +:root { + /* Font families */ + --bui-font-regular: system-ui; + --bui-font-monospace: ui-monospace, 'Menlo', 'Monaco', 'Consolas', + 'Liberation Mono', 'Courier New', monospace; + + /* Font weights */ + --bui-font-weight-regular: 400; + --bui-font-weight-bold: 600; + + /* Font sizes */ + --bui-font-size-1: 0.625rem; /* 10px */ + --bui-font-size-2: 0.75rem; /* 12px */ + --bui-font-size-3: 0.875rem; /* 14px */ + --bui-font-size-4: 1rem; /* 16px */ + --bui-font-size-5: 1.25rem; /* 20px */ + --bui-font-size-6: 1.5rem; /* 24px */ + --bui-font-size-7: 2rem; /* 32px */ + --bui-font-size-8: 3rem; /* 48px */ + --bui-font-size-9: 4rem; /* 64px */ + --bui-font-size-10: 5.75rem; /* 92px */ + + /* Spacing */ + --bui-space: 0.25rem; /* This is the spacing multiplier */ + --bui-space-0_5: calc(var(--bui-space) * 0.5); /* 2px */ + --bui-space-1: var(--bui-space); /* 4px */ + --bui-space-1_5: calc(var(--bui-space) * 1.5); /* 6px */ + --bui-space-2: calc(var(--bui-space) * 2); /* 8px */ + --bui-space-3: calc(var(--bui-space) * 3); /* 12px */ + --bui-space-4: calc(var(--bui-space) * 4); /* 16px */ + --bui-space-5: calc(var(--bui-space) * 5); /* 20px */ + --bui-space-6: calc(var(--bui-space) * 6); /* 24px */ + --bui-space-7: calc(var(--bui-space) * 7); /* 28px */ + --bui-space-8: calc(var(--bui-space) * 8); /* 32px */ + --bui-space-9: calc(var(--bui-space) * 9); /* 36px */ + --bui-space-10: calc(var(--bui-space) * 10); /* 40px */ + --bui-space-11: calc(var(--bui-space) * 11); /* 44px */ + --bui-space-12: calc(var(--bui-space) * 12); /* 48px */ + --bui-space-13: calc(var(--bui-space) * 13); /* 52px */ + --bui-space-14: calc(var(--bui-space) * 14); /* 56px */ + + /* Radius */ + --bui-radius-1: calc(0.125rem); + --bui-radius-2: calc(0.25rem); + --bui-radius-3: calc(0.5rem); + --bui-radius-4: calc(0.75rem); + --bui-radius-5: calc(1rem); + --bui-radius-6: calc(1.25rem); + --bui-radius-full: 9999px; + + /* Base Colors */ + --bui-black: #000000; + --bui-white: #ffffff; + + /* Gray scale */ + --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; + + /* Background Colors */ + --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: rgba(31, 84, 147, 0.4); + --bui-bg-tint-pressed: rgba(31, 84, 147, 0.6); + --bui-bg-tint-disabled: #ebebeb; + --bui-bg-danger: #feebe7; + --bui-bg-warning: #fff2b2; + --bui-bg-success: #e6f6eb; + + /* Foreground Colors */ + --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; + + /* Border Colors */ + --bui-border: rgba(0, 0, 0, 0.1); + --bui-border-hover: rgba(0, 0, 0, 0.2); + --bui-border-pressed: rgba(0, 0, 0, 0.4); + --bui-border-disabled: rgba(0, 0, 0, 0.1); + --bui-border-danger: #f87a7a; + --bui-border-warning: #e36d05; + --bui-border-success: #53db83; + + /* Special Colors */ + --bui-ring: #1f5493; + --bui-scrollbar: #a0a0a03b; + --bui-scrollbar-thumb: #a0a0a0; + + --bui-animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +/* Dark theme tokens */ +[data-theme='dark'] { + /* Gray scale */ + --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; + + /* Background Colors */ + --bui-bg: #333333; + --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: #222222; + --bui-bg-tint: transparent; + --bui-bg-tint-hover: rgba(156, 201, 255, 0.12); + --bui-bg-tint-pressed: rgba(156, 201, 255, 0.16); + --bui-bg-tint-disabled: transparent; + --bui-bg-danger: #3b1219; + --bui-bg-warning: #302008; + --bui-bg-success: #132d21; + + /* Foreground Colors */ + --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; + + /* Border Colors */ + --bui-border: rgba(255, 255, 255, 0.12); + --bui-border-hover: rgba(255, 255, 255, 0.4); + --bui-border-pressed: rgba(255, 255, 255, 0.5); + --bui-border-disabled: rgba(255, 255, 255, 0.2); + --bui-border-danger: #f87a7a; + --bui-border-warning: #e36d05; + --bui-border-success: #53db83; + + /* Special Colors */ + --bui-ring: #1f5493; + --bui-scrollbar: #3636363a; + --bui-scrollbar-thumb: #575757; +} diff --git a/packages/canon/src/css/normalize.css b/packages/ui/src/css/normalize.css similarity index 100% rename from packages/canon/src/css/normalize.css rename to packages/ui/src/css/normalize.css diff --git a/packages/canon/src/css/stories.module.css b/packages/ui/src/css/stories.module.css similarity index 100% rename from packages/canon/src/css/stories.module.css rename to packages/ui/src/css/stories.module.css diff --git a/packages/ui/src/css/storybook.css b/packages/ui/src/css/storybook.css new file mode 100644 index 0000000000..57f50dd888 --- /dev/null +++ b/packages/ui/src/css/storybook.css @@ -0,0 +1,38 @@ +:root { + --sb-panel-radius: 0; + --sb-panel-top: 0; + --sb-panel-bottom: 0; + --sb-panel-left: 0; + --sb-panel-right: 0; + --sb-sidebar-border: none; + --sb-sidebar-border-right: 1px solid var(--bui-border); + --sb-sidebar-bg: #000; + --sb-options-border: none; + --sb-options-border-left: 1px solid var(--bui-border); + --sb-content-padding-inline: 250px; +} + +[data-theme='dark'] { + --sb-sidebar-bg: var(--bui-bg-surface-1); +} + +[data-theme-name='spotify'] { + --sb-panel-radius: var(--bui-radius-3); + --sb-panel-top: 8px; + --sb-panel-bottom: 8px; + --sb-panel-left: 8px; + --sb-panel-right: 8px; + --sb-sidebar-border: none; + --sb-sidebar-border-right: none; + --sb-sidebar-bg: var(--bui-bg-surface-1); + --sb-options-border: none; + --sb-options-border-left: none; + --sb-content-padding-inline: 258px; +} + +[data-theme-name='spotify'][data-theme='light'] { + --sb-sidebar-border: 1px solid var(--bui-border); + --sb-sidebar-border-right: 1px solid var(--bui-border); + --sb-options-border: 1px solid var(--bui-border); + --sb-options-border-left: 1px solid var(--bui-border); +} diff --git a/packages/canon/src/css/styles.css b/packages/ui/src/css/styles.css similarity index 100% rename from packages/canon/src/css/styles.css rename to packages/ui/src/css/styles.css diff --git a/packages/canon/src/css/utilities.css b/packages/ui/src/css/utilities.css similarity index 100% rename from packages/canon/src/css/utilities.css rename to packages/ui/src/css/utilities.css diff --git a/packages/canon/src/css/utilities/display.css b/packages/ui/src/css/utilities/display.css similarity index 56% rename from packages/canon/src/css/utilities/display.css rename to packages/ui/src/css/utilities/display.css index 8c353730ca..179d80f860 100644 --- a/packages/canon/src/css/utilities/display.css +++ b/packages/ui/src/css/utilities/display.css @@ -1,110 +1,110 @@ -.cu-display-none { +.bui-display-none { display: none; } -.cu-display-inline { +.bui-display-inline { display: inline; } -.cu-display-inline-block { +.bui-display-inline-block { display: inline-block; } -.cu-display-block { +.bui-display-block { display: block; } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-display-none { + .xs\:bui-display-none { display: none; } - .xs\:cu-display-inline { + .xs\:bui-display-inline { display: inline; } - .xs\:cu-display-inline-block { + .xs\:bui-display-inline-block { display: inline-block; } - .xs\:cu-display-block { + .xs\:bui-display-block { display: block; } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-display-none { + .sm\:bui-display-none { display: none; } - .sm\:cu-display-inline { + .sm\:bui-display-inline { display: inline; } - .sm\:cu-display-inline-block { + .sm\:bui-display-inline-block { display: inline-block; } - .sm\:cu-display-block { + .sm\:bui-display-block { display: block; } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-display-none { + .md\:bui-display-none { display: none; } - .md\:cu-display-inline { + .md\:bui-display-inline { display: inline; } - .md\:cu-display-inline-block { + .md\:bui-display-inline-block { display: inline-block; } - .md\:cu-display-block { + .md\:bui-display-block { display: block; } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-display-none { + .lg\:bui-display-none { display: none; } - .lg\:cu-display-inline { + .lg\:bui-display-inline { display: inline; } - .lg\:cu-display-inline-block { + .lg\:bui-display-inline-block { display: inline-block; } - .lg\:cu-display-block { + .lg\:bui-display-block { display: block; } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-display-none { + .xl\:bui-display-none { display: none; } - .xl\:cu-display-inline { + .xl\:bui-display-inline { display: inline; } - .xl\:cu-display-inline-block { + .xl\:bui-display-inline-block { display: inline-block; } - .xl\:cu-display-block { + .xl\:bui-display-block { display: block; } } diff --git a/packages/canon/src/css/utilities/flex.css b/packages/ui/src/css/utilities/flex.css similarity index 60% rename from packages/canon/src/css/utilities/flex.css rename to packages/ui/src/css/utilities/flex.css index 5311aac3e8..d68c63556f 100644 --- a/packages/canon/src/css/utilities/flex.css +++ b/packages/ui/src/css/utilities/flex.css @@ -1,302 +1,302 @@ -.cu-align-start { +.bui-align-start { align-items: start; } -.cu-align-center { +.bui-align-center { align-items: center; } -.cu-align-end { +.bui-align-end { align-items: end; } -.cu-align-stretch { +.bui-align-stretch { align-items: stretch; } -.cu-jc-start { +.bui-jc-start { justify-content: start; } -.cu-jc-center { +.bui-jc-center { justify-content: center; } -.cu-jc-end { +.bui-jc-end { justify-content: end; } -.cu-jc-between { +.bui-jc-between { justify-content: space-between; } -.cu-fd-row { +.bui-fd-row { flex-direction: row; } -.cu-fd-column { +.bui-fd-column { flex-direction: column; } -.cu-fd-row-reverse { +.bui-fd-row-reverse { flex-direction: row-reverse; } -.cu-fd-column-reverse { +.bui-fd-column-reverse { flex-direction: column-reverse; } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-align-start { + .xs\:bui-align-start { align-items: start; } - .xs\:cu-align-center { + .xs\:bui-align-center { align-items: center; } - .xs\:cu-align-end { + .xs\:bui-align-end { align-items: end; } - .xs\:cu-align-stretch { + .xs\:bui-align-stretch { align-items: stretch; } - .xs\:cu-jc-start { + .xs\:bui-jc-start { justify-content: start; } - .xs\:cu-jc-center { + .xs\:bui-jc-center { justify-content: center; } - .xs\:cu-jc-end { + .xs\:bui-jc-end { justify-content: end; } - .xs\:cu-jc-between { + .xs\:bui-jc-between { justify-content: space-between; } - .xs\:cu-fd-row { + .xs\:bui-fd-row { flex-direction: row; } - .xs\:cu-fd-column { + .xs\:bui-fd-column { flex-direction: column; } - .xs\:cu-fd-row-reverse { + .xs\:bui-fd-row-reverse { flex-direction: row-reverse; } - .xs\:cu-fd-column-reverse { + .xs\:bui-fd-column-reverse { flex-direction: column-reverse; } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-align-start { + .sm\:bui-align-start { align-items: start; } - .sm\:cu-align-center { + .sm\:bui-align-center { align-items: center; } - .sm\:cu-align-end { + .sm\:bui-align-end { align-items: end; } - .sm\:cu-align-stretch { + .sm\:bui-align-stretch { align-items: stretch; } - .sm\:cu-jc-start { + .sm\:bui-jc-start { justify-content: start; } - .sm\:cu-jc-center { + .sm\:bui-jc-center { justify-content: center; } - .sm\:cu-jc-end { + .sm\:bui-jc-end { justify-content: end; } - .sm\:cu-jc-between { + .sm\:bui-jc-between { justify-content: space-between; } - .sm\:cu-fd-row { + .sm\:bui-fd-row { flex-direction: row; } - .sm\:cu-fd-column { + .sm\:bui-fd-column { flex-direction: column; } - .sm\:cu-fd-row-reverse { + .sm\:bui-fd-row-reverse { flex-direction: row-reverse; } - .sm\:cu-fd-column-reverse { + .sm\:bui-fd-column-reverse { flex-direction: column-reverse; } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-align-start { + .md\:bui-align-start { align-items: start; } - .md\:cu-align-center { + .md\:bui-align-center { align-items: center; } - .md\:cu-align-end { + .md\:bui-align-end { align-items: end; } - .md\:cu-align-stretch { + .md\:bui-align-stretch { align-items: stretch; } - .md\:cu-jc-start { + .md\:bui-jc-start { justify-content: start; } - .md\:cu-jc-center { + .md\:bui-jc-center { justify-content: center; } - .md\:cu-jc-end { + .md\:bui-jc-end { justify-content: end; } - .md\:cu-jc-between { + .md\:bui-jc-between { justify-content: space-between; } - .md\:cu-fd-row { + .md\:bui-fd-row { flex-direction: row; } - .md\:cu-fd-column { + .md\:bui-fd-column { flex-direction: column; } - .md\:cu-fd-row-reverse { + .md\:bui-fd-row-reverse { flex-direction: row-reverse; } - .md\:cu-fd-column-reverse { + .md\:bui-fd-column-reverse { flex-direction: column-reverse; } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-align-start { + .lg\:bui-align-start { align-items: start; } - .lg\:cu-align-center { + .lg\:bui-align-center { align-items: center; } - .lg\:cu-align-end { + .lg\:bui-align-end { align-items: end; } - .lg\:cu-align-stretch { + .lg\:bui-align-stretch { align-items: stretch; } - .lg\:cu-jc-start { + .lg\:bui-jc-start { justify-content: start; } - .lg\:cu-jc-center { + .lg\:bui-jc-center { justify-content: center; } - .lg\:cu-jc-end { + .lg\:bui-jc-end { justify-content: end; } - .lg\:cu-jc-between { + .lg\:bui-jc-between { justify-content: space-between; } - .lg\:cu-fd-row { + .lg\:bui-fd-row { flex-direction: row; } - .lg\:cu-fd-column { + .lg\:bui-fd-column { flex-direction: column; } - .lg\:cu-fd-row-reverse { + .lg\:bui-fd-row-reverse { flex-direction: row-reverse; } - .lg\:cu-fd-column-reverse { + .lg\:bui-fd-column-reverse { flex-direction: column-reverse; } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-align-start { + .xl\:bui-align-start { align-items: start; } - .xl\:cu-align-center { + .xl\:bui-align-center { align-items: center; } - .xl\:cu-align-end { + .xl\:bui-align-end { align-items: end; } - .xl\:cu-align-stretch { + .xl\:bui-align-stretch { align-items: stretch; } - .xl\:cu-jc-start { + .xl\:bui-jc-start { justify-content: start; } - .xl\:cu-jc-center { + .xl\:bui-jc-center { justify-content: center; } - .xl\:cu-jc-end { + .xl\:bui-jc-end { justify-content: end; } - .xl\:cu-jc-between { + .xl\:bui-jc-between { justify-content: space-between; } - .xl\:cu-fd-row { + .xl\:bui-fd-row { flex-direction: row; } - .xl\:cu-fd-column { + .xl\:bui-fd-column { flex-direction: column; } - .xl\:cu-fd-row-reverse { + .xl\:bui-fd-row-reverse { flex-direction: row-reverse; } - .xl\:cu-fd-column-reverse { + .xl\:bui-fd-column-reverse { flex-direction: column-reverse; } } diff --git a/packages/ui/src/css/utilities/gap.css b/packages/ui/src/css/utilities/gap.css new file mode 100644 index 0000000000..ec4168fa6b --- /dev/null +++ b/packages/ui/src/css/utilities/gap.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/canon/src/css/utilities/grid.css b/packages/ui/src/css/utilities/grid.css similarity index 62% rename from packages/canon/src/css/utilities/grid.css rename to packages/ui/src/css/utilities/grid.css index a0afe55533..11de40bd7f 100644 --- a/packages/canon/src/css/utilities/grid.css +++ b/packages/ui/src/css/utilities/grid.css @@ -1,1292 +1,1292 @@ -.cu-columns-1 { +.bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } -.cu-columns-2 { +.bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } -.cu-columns-3 { +.bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } -.cu-columns-4 { +.bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } -.cu-columns-5 { +.bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } -.cu-columns-6 { +.bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } -.cu-columns-7 { +.bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } -.cu-columns-8 { +.bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } -.cu-columns-9 { +.bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } -.cu-columns-10 { +.bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } -.cu-columns-11 { +.bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } -.cu-columns-12 { +.bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } -.cu-columns-auto { +.bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } -.cu-col-span-1 { +.bui-col-span-1 { grid-column: span 1 / span 1; } -.cu-col-span-2 { +.bui-col-span-2 { grid-column: span 2 / span 2; } -.cu-col-span-3 { +.bui-col-span-3 { grid-column: span 3 / span 3; } -.cu-col-span-4 { +.bui-col-span-4 { grid-column: span 4 / span 4; } -.cu-col-span-5 { +.bui-col-span-5 { grid-column: span 5 / span 5; } -.cu-col-span-6 { +.bui-col-span-6 { grid-column: span 6 / span 6; } -.cu-col-span-7 { +.bui-col-span-7 { grid-column: span 7 / span 7; } -.cu-col-span-8 { +.bui-col-span-8 { grid-column: span 8 / span 8; } -.cu-col-span-9 { +.bui-col-span-9 { grid-column: span 9 / span 9; } -.cu-col-span-10 { +.bui-col-span-10 { grid-column: span 10 / span 10; } -.cu-col-span-11 { +.bui-col-span-11 { grid-column: span 11 / span 11; } -.cu-col-span-12 { +.bui-col-span-12 { grid-column: span 12 / span 12; } -.cu-col-span-auto { +.bui-col-span-auto { grid-column: span auto / span auto; } -.cu-col-start-1 { +.bui-col-start-1 { grid-column-start: 1; } -.cu-col-start-2 { +.bui-col-start-2 { grid-column-start: 2; } -.cu-col-start-3 { +.bui-col-start-3 { grid-column-start: 3; } -.cu-col-start-4 { +.bui-col-start-4 { grid-column-start: 4; } -.cu-col-start-5 { +.bui-col-start-5 { grid-column-start: 5; } -.cu-col-start-6 { +.bui-col-start-6 { grid-column-start: 6; } -.cu-col-start-7 { +.bui-col-start-7 { grid-column-start: 7; } -.cu-col-start-8 { +.bui-col-start-8 { grid-column-start: 8; } -.cu-col-start-9 { +.bui-col-start-9 { grid-column-start: 9; } -.cu-col-start-10 { +.bui-col-start-10 { grid-column-start: 10; } -.cu-col-start-11 { +.bui-col-start-11 { grid-column-start: 11; } -.cu-col-start-12 { +.bui-col-start-12 { grid-column-start: 12; } -.cu-col-start-13 { +.bui-col-start-13 { grid-column-start: 13; } -.cu-col-start-auto { +.bui-col-start-auto { grid-column-start: auto; } -.cu-col-end-1 { +.bui-col-end-1 { grid-column-end: 1; } -.cu-col-end-2 { +.bui-col-end-2 { grid-column-end: 2; } -.cu-col-end-3 { +.bui-col-end-3 { grid-column-end: 3; } -.cu-col-end-4 { +.bui-col-end-4 { grid-column-end: 4; } -.cu-col-end-5 { +.bui-col-end-5 { grid-column-end: 5; } -.cu-col-end-6 { +.bui-col-end-6 { grid-column-end: 6; } -.cu-col-end-7 { +.bui-col-end-7 { grid-column-end: 7; } -.cu-col-end-8 { +.bui-col-end-8 { grid-column-end: 8; } -.cu-col-end-9 { +.bui-col-end-9 { grid-column-end: 9; } -.cu-col-end-10 { +.bui-col-end-10 { grid-column-end: 10; } -.cu-col-end-11 { +.bui-col-end-11 { grid-column-end: 11; } -.cu-col-end-12 { +.bui-col-end-12 { grid-column-end: 12; } -.cu-col-end-13 { +.bui-col-end-13 { grid-column-end: 13; } -.cu-col-end-auto { +.bui-col-end-auto { grid-column-end: auto; } -.cu-row-span-1 { +.bui-row-span-1 { grid-row: span 1 / span 1; } -.cu-row-span-2 { +.bui-row-span-2 { grid-row: span 2 / span 2; } -.cu-row-span-3 { +.bui-row-span-3 { grid-row: span 3 / span 3; } -.cu-row-span-4 { +.bui-row-span-4 { grid-row: span 4 / span 4; } -.cu-row-span-5 { +.bui-row-span-5 { grid-row: span 5 / span 5; } -.cu-row-span-6 { +.bui-row-span-6 { grid-row: span 6 / span 6; } -.cu-row-span-7 { +.bui-row-span-7 { grid-row: span 7 / span 7; } -.cu-row-span-8 { +.bui-row-span-8 { grid-row: span 8 / span 8; } -.cu-row-span-9 { +.bui-row-span-9 { grid-row: span 9 / span 9; } -.cu-row-span-10 { +.bui-row-span-10 { grid-row: span 10 / span 10; } -.cu-row-span-11 { +.bui-row-span-11 { grid-row: span 11 / span 11; } -.cu-row-span-12 { +.bui-row-span-12 { grid-row: span 12 / span 12; } -.cu-row-span-auto { +.bui-row-span-auto { grid-row: span auto / span auto; } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-columns-1 { + .xs\:bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .xs\:cu-columns-2 { + .xs\:bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .xs\:cu-columns-3 { + .xs\:bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .xs\:cu-columns-4 { + .xs\:bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .xs\:cu-columns-5 { + .xs\:bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .xs\:cu-columns-6 { + .xs\:bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } - .xs\:cu-columns-7 { + .xs\:bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } - .xs\:cu-columns-8 { + .xs\:bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } - .xs\:cu-columns-9 { + .xs\:bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } - .xs\:cu-columns-10 { + .xs\:bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } - .xs\:cu-columns-11 { + .xs\:bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } - .xs\:cu-columns-12 { + .xs\:bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } - .xs\:cu-columns-auto { + .xs\:bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } - .xs\:cu-col-span-1 { + .xs\:bui-col-span-1 { grid-column: span 1 / span 1; } - .xs\:cu-col-span-2 { + .xs\:bui-col-span-2 { grid-column: span 2 / span 2; } - .xs\:cu-col-span-3 { + .xs\:bui-col-span-3 { grid-column: span 3 / span 3; } - .xs\:cu-col-span-4 { + .xs\:bui-col-span-4 { grid-column: span 4 / span 4; } - .xs\:cu-col-span-5 { + .xs\:bui-col-span-5 { grid-column: span 5 / span 5; } - .xs\:cu-col-span-6 { + .xs\:bui-col-span-6 { grid-column: span 6 / span 6; } - .xs\:cu-col-span-7 { + .xs\:bui-col-span-7 { grid-column: span 7 / span 7; } - .xs\:cu-col-span-8 { + .xs\:bui-col-span-8 { grid-column: span 8 / span 8; } - .xs\:cu-col-span-9 { + .xs\:bui-col-span-9 { grid-column: span 9 / span 9; } - .xs\:cu-col-span-10 { + .xs\:bui-col-span-10 { grid-column: span 10 / span 10; } - .xs\:cu-col-span-11 { + .xs\:bui-col-span-11 { grid-column: span 11 / span 11; } - .xs\:cu-col-span-12 { + .xs\:bui-col-span-12 { grid-column: span 12 / span 12; } - .xs\:cu-col-span-auto { + .xs\:bui-col-span-auto { grid-column: span auto / span auto; } - .xs\:cu-col-start-1 { + .xs\:bui-col-start-1 { grid-column-start: 1; } - .xs\:cu-col-start-2 { + .xs\:bui-col-start-2 { grid-column-start: 2; } - .xs\:cu-col-start-3 { + .xs\:bui-col-start-3 { grid-column-start: 3; } - .xs\:cu-col-start-4 { + .xs\:bui-col-start-4 { grid-column-start: 4; } - .xs\:cu-col-start-5 { + .xs\:bui-col-start-5 { grid-column-start: 5; } - .xs\:cu-col-start-6 { + .xs\:bui-col-start-6 { grid-column-start: 6; } - .xs\:cu-col-start-7 { + .xs\:bui-col-start-7 { grid-column-start: 7; } - .xs\:cu-col-start-8 { + .xs\:bui-col-start-8 { grid-column-start: 8; } - .xs\:cu-col-start-9 { + .xs\:bui-col-start-9 { grid-column-start: 9; } - .xs\:cu-col-start-10 { + .xs\:bui-col-start-10 { grid-column-start: 10; } - .xs\:cu-col-start-11 { + .xs\:bui-col-start-11 { grid-column-start: 11; } - .xs\:cu-col-start-12 { + .xs\:bui-col-start-12 { grid-column-start: 12; } - .xs\:cu-col-start-13 { + .xs\:bui-col-start-13 { grid-column-start: 13; } - .xs\:cu-col-start-auto { + .xs\:bui-col-start-auto { grid-column-start: auto; } - .xs\:cu-col-end-1 { + .xs\:bui-col-end-1 { grid-column-end: 1; } - .xs\:cu-col-end-2 { + .xs\:bui-col-end-2 { grid-column-end: 2; } - .xs\:cu-col-end-3 { + .xs\:bui-col-end-3 { grid-column-end: 3; } - .xs\:cu-col-end-4 { + .xs\:bui-col-end-4 { grid-column-end: 4; } - .xs\:cu-col-end-5 { + .xs\:bui-col-end-5 { grid-column-end: 5; } - .xs\:cu-col-end-6 { + .xs\:bui-col-end-6 { grid-column-end: 6; } - .xs\:cu-col-end-7 { + .xs\:bui-col-end-7 { grid-column-end: 7; } - .xs\:cu-col-end-8 { + .xs\:bui-col-end-8 { grid-column-end: 8; } - .xs\:cu-col-end-9 { + .xs\:bui-col-end-9 { grid-column-end: 9; } - .xs\:cu-col-end-10 { + .xs\:bui-col-end-10 { grid-column-end: 10; } - .xs\:cu-col-end-11 { + .xs\:bui-col-end-11 { grid-column-end: 11; } - .xs\:cu-col-end-12 { + .xs\:bui-col-end-12 { grid-column-end: 12; } - .xs\:cu-col-end-13 { + .xs\:bui-col-end-13 { grid-column-end: 13; } - .xs\:cu-col-end-auto { + .xs\:bui-col-end-auto { grid-column-end: auto; } - .xs\:cu-row-span-1 { + .xs\:bui-row-span-1 { grid-row: span 1 / span 1; } - .xs\:cu-row-span-2 { + .xs\:bui-row-span-2 { grid-row: span 2 / span 2; } - .xs\:cu-row-span-3 { + .xs\:bui-row-span-3 { grid-row: span 3 / span 3; } - .xs\:cu-row-span-4 { + .xs\:bui-row-span-4 { grid-row: span 4 / span 4; } - .xs\:cu-row-span-5 { + .xs\:bui-row-span-5 { grid-row: span 5 / span 5; } - .xs\:cu-row-span-6 { + .xs\:bui-row-span-6 { grid-row: span 6 / span 6; } - .xs\:cu-row-span-7 { + .xs\:bui-row-span-7 { grid-row: span 7 / span 7; } - .xs\:cu-row-span-8 { + .xs\:bui-row-span-8 { grid-row: span 8 / span 8; } - .xs\:cu-row-span-9 { + .xs\:bui-row-span-9 { grid-row: span 9 / span 9; } - .xs\:cu-row-span-10 { + .xs\:bui-row-span-10 { grid-row: span 10 / span 10; } - .xs\:cu-row-span-11 { + .xs\:bui-row-span-11 { grid-row: span 11 / span 11; } - .xs\:cu-row-span-12 { + .xs\:bui-row-span-12 { grid-row: span 12 / span 12; } - .xs\:cu-row-span-auto { + .xs\:bui-row-span-auto { grid-row: span auto / span auto; } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-columns-1 { + .sm\:bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .sm\:cu-columns-2 { + .sm\:bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .sm\:cu-columns-3 { + .sm\:bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .sm\:cu-columns-4 { + .sm\:bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .sm\:cu-columns-5 { + .sm\:bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .sm\:cu-columns-6 { + .sm\:bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } - .sm\:cu-columns-7 { + .sm\:bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } - .sm\:cu-columns-8 { + .sm\:bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } - .sm\:cu-columns-9 { + .sm\:bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } - .sm\:cu-columns-10 { + .sm\:bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } - .sm\:cu-columns-11 { + .sm\:bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } - .sm\:cu-columns-12 { + .sm\:bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } - .sm\:cu-columns-auto { + .sm\:bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } - .sm\:cu-col-span-1 { + .sm\:bui-col-span-1 { grid-column: span 1 / span 1; } - .sm\:cu-col-span-2 { + .sm\:bui-col-span-2 { grid-column: span 2 / span 2; } - .sm\:cu-col-span-3 { + .sm\:bui-col-span-3 { grid-column: span 3 / span 3; } - .sm\:cu-col-span-4 { + .sm\:bui-col-span-4 { grid-column: span 4 / span 4; } - .sm\:cu-col-span-5 { + .sm\:bui-col-span-5 { grid-column: span 5 / span 5; } - .sm\:cu-col-span-6 { + .sm\:bui-col-span-6 { grid-column: span 6 / span 6; } - .sm\:cu-col-span-7 { + .sm\:bui-col-span-7 { grid-column: span 7 / span 7; } - .sm\:cu-col-span-8 { + .sm\:bui-col-span-8 { grid-column: span 8 / span 8; } - .sm\:cu-col-span-9 { + .sm\:bui-col-span-9 { grid-column: span 9 / span 9; } - .sm\:cu-col-span-10 { + .sm\:bui-col-span-10 { grid-column: span 10 / span 10; } - .sm\:cu-col-span-11 { + .sm\:bui-col-span-11 { grid-column: span 11 / span 11; } - .sm\:cu-col-span-12 { + .sm\:bui-col-span-12 { grid-column: span 12 / span 12; } - .sm\:cu-col-span-auto { + .sm\:bui-col-span-auto { grid-column: span auto / span auto; } - .sm\:cu-col-start-1 { + .sm\:bui-col-start-1 { grid-column-start: 1; } - .sm\:cu-col-start-2 { + .sm\:bui-col-start-2 { grid-column-start: 2; } - .sm\:cu-col-start-3 { + .sm\:bui-col-start-3 { grid-column-start: 3; } - .sm\:cu-col-start-4 { + .sm\:bui-col-start-4 { grid-column-start: 4; } - .sm\:cu-col-start-5 { + .sm\:bui-col-start-5 { grid-column-start: 5; } - .sm\:cu-col-start-6 { + .sm\:bui-col-start-6 { grid-column-start: 6; } - .sm\:cu-col-start-7 { + .sm\:bui-col-start-7 { grid-column-start: 7; } - .sm\:cu-col-start-8 { + .sm\:bui-col-start-8 { grid-column-start: 8; } - .sm\:cu-col-start-9 { + .sm\:bui-col-start-9 { grid-column-start: 9; } - .sm\:cu-col-start-10 { + .sm\:bui-col-start-10 { grid-column-start: 10; } - .sm\:cu-col-start-11 { + .sm\:bui-col-start-11 { grid-column-start: 11; } - .sm\:cu-col-start-12 { + .sm\:bui-col-start-12 { grid-column-start: 12; } - .sm\:cu-col-start-13 { + .sm\:bui-col-start-13 { grid-column-start: 13; } - .sm\:cu-col-start-auto { + .sm\:bui-col-start-auto { grid-column-start: auto; } - .sm\:cu-col-end-1 { + .sm\:bui-col-end-1 { grid-column-end: 1; } - .sm\:cu-col-end-2 { + .sm\:bui-col-end-2 { grid-column-end: 2; } - .sm\:cu-col-end-3 { + .sm\:bui-col-end-3 { grid-column-end: 3; } - .sm\:cu-col-end-4 { + .sm\:bui-col-end-4 { grid-column-end: 4; } - .sm\:cu-col-end-5 { + .sm\:bui-col-end-5 { grid-column-end: 5; } - .sm\:cu-col-end-6 { + .sm\:bui-col-end-6 { grid-column-end: 6; } - .sm\:cu-col-end-7 { + .sm\:bui-col-end-7 { grid-column-end: 7; } - .sm\:cu-col-end-8 { + .sm\:bui-col-end-8 { grid-column-end: 8; } - .sm\:cu-col-end-9 { + .sm\:bui-col-end-9 { grid-column-end: 9; } - .sm\:cu-col-end-10 { + .sm\:bui-col-end-10 { grid-column-end: 10; } - .sm\:cu-col-end-11 { + .sm\:bui-col-end-11 { grid-column-end: 11; } - .sm\:cu-col-end-12 { + .sm\:bui-col-end-12 { grid-column-end: 12; } - .sm\:cu-col-end-13 { + .sm\:bui-col-end-13 { grid-column-end: 13; } - .sm\:cu-col-end-auto { + .sm\:bui-col-end-auto { grid-column-end: auto; } - .sm\:cu-row-span-1 { + .sm\:bui-row-span-1 { grid-row: span 1 / span 1; } - .sm\:cu-row-span-2 { + .sm\:bui-row-span-2 { grid-row: span 2 / span 2; } - .sm\:cu-row-span-3 { + .sm\:bui-row-span-3 { grid-row: span 3 / span 3; } - .sm\:cu-row-span-4 { + .sm\:bui-row-span-4 { grid-row: span 4 / span 4; } - .sm\:cu-row-span-5 { + .sm\:bui-row-span-5 { grid-row: span 5 / span 5; } - .sm\:cu-row-span-6 { + .sm\:bui-row-span-6 { grid-row: span 6 / span 6; } - .sm\:cu-row-span-7 { + .sm\:bui-row-span-7 { grid-row: span 7 / span 7; } - .sm\:cu-row-span-8 { + .sm\:bui-row-span-8 { grid-row: span 8 / span 8; } - .sm\:cu-row-span-9 { + .sm\:bui-row-span-9 { grid-row: span 9 / span 9; } - .sm\:cu-row-span-10 { + .sm\:bui-row-span-10 { grid-row: span 10 / span 10; } - .sm\:cu-row-span-11 { + .sm\:bui-row-span-11 { grid-row: span 11 / span 11; } - .sm\:cu-row-span-12 { + .sm\:bui-row-span-12 { grid-row: span 12 / span 12; } - .sm\:cu-row-span-auto { + .sm\:bui-row-span-auto { grid-row: span auto / span auto; } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-columns-1 { + .md\:bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .md\:cu-columns-2 { + .md\:bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .md\:cu-columns-3 { + .md\:bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .md\:cu-columns-4 { + .md\:bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .md\:cu-columns-5 { + .md\:bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .md\:cu-columns-6 { + .md\:bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } - .md\:cu-columns-7 { + .md\:bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } - .md\:cu-columns-8 { + .md\:bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } - .md\:cu-columns-9 { + .md\:bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } - .md\:cu-columns-10 { + .md\:bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } - .md\:cu-columns-11 { + .md\:bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } - .md\:cu-columns-12 { + .md\:bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } - .md\:cu-columns-auto { + .md\:bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } - .md\:cu-col-span-1 { + .md\:bui-col-span-1 { grid-column: span 1 / span 1; } - .md\:cu-col-span-2 { + .md\:bui-col-span-2 { grid-column: span 2 / span 2; } - .md\:cu-col-span-3 { + .md\:bui-col-span-3 { grid-column: span 3 / span 3; } - .md\:cu-col-span-4 { + .md\:bui-col-span-4 { grid-column: span 4 / span 4; } - .md\:cu-col-span-5 { + .md\:bui-col-span-5 { grid-column: span 5 / span 5; } - .md\:cu-col-span-6 { + .md\:bui-col-span-6 { grid-column: span 6 / span 6; } - .md\:cu-col-span-7 { + .md\:bui-col-span-7 { grid-column: span 7 / span 7; } - .md\:cu-col-span-8 { + .md\:bui-col-span-8 { grid-column: span 8 / span 8; } - .md\:cu-col-span-9 { + .md\:bui-col-span-9 { grid-column: span 9 / span 9; } - .md\:cu-col-span-10 { + .md\:bui-col-span-10 { grid-column: span 10 / span 10; } - .md\:cu-col-span-11 { + .md\:bui-col-span-11 { grid-column: span 11 / span 11; } - .md\:cu-col-span-12 { + .md\:bui-col-span-12 { grid-column: span 12 / span 12; } - .md\:cu-col-span-auto { + .md\:bui-col-span-auto { grid-column: span auto / span auto; } - .md\:cu-col-start-1 { + .md\:bui-col-start-1 { grid-column-start: 1; } - .md\:cu-col-start-2 { + .md\:bui-col-start-2 { grid-column-start: 2; } - .md\:cu-col-start-3 { + .md\:bui-col-start-3 { grid-column-start: 3; } - .md\:cu-col-start-4 { + .md\:bui-col-start-4 { grid-column-start: 4; } - .md\:cu-col-start-5 { + .md\:bui-col-start-5 { grid-column-start: 5; } - .md\:cu-col-start-6 { + .md\:bui-col-start-6 { grid-column-start: 6; } - .md\:cu-col-start-7 { + .md\:bui-col-start-7 { grid-column-start: 7; } - .md\:cu-col-start-8 { + .md\:bui-col-start-8 { grid-column-start: 8; } - .md\:cu-col-start-9 { + .md\:bui-col-start-9 { grid-column-start: 9; } - .md\:cu-col-start-10 { + .md\:bui-col-start-10 { grid-column-start: 10; } - .md\:cu-col-start-11 { + .md\:bui-col-start-11 { grid-column-start: 11; } - .md\:cu-col-start-12 { + .md\:bui-col-start-12 { grid-column-start: 12; } - .md\:cu-col-start-13 { + .md\:bui-col-start-13 { grid-column-start: 13; } - .md\:cu-col-start-auto { + .md\:bui-col-start-auto { grid-column-start: auto; } - .md\:cu-col-end-1 { + .md\:bui-col-end-1 { grid-column-end: 1; } - .md\:cu-col-end-2 { + .md\:bui-col-end-2 { grid-column-end: 2; } - .md\:cu-col-end-3 { + .md\:bui-col-end-3 { grid-column-end: 3; } - .md\:cu-col-end-4 { + .md\:bui-col-end-4 { grid-column-end: 4; } - .md\:cu-col-end-5 { + .md\:bui-col-end-5 { grid-column-end: 5; } - .md\:cu-col-end-6 { + .md\:bui-col-end-6 { grid-column-end: 6; } - .md\:cu-col-end-7 { + .md\:bui-col-end-7 { grid-column-end: 7; } - .md\:cu-col-end-8 { + .md\:bui-col-end-8 { grid-column-end: 8; } - .md\:cu-col-end-9 { + .md\:bui-col-end-9 { grid-column-end: 9; } - .md\:cu-col-end-10 { + .md\:bui-col-end-10 { grid-column-end: 10; } - .md\:cu-col-end-11 { + .md\:bui-col-end-11 { grid-column-end: 11; } - .md\:cu-col-end-12 { + .md\:bui-col-end-12 { grid-column-end: 12; } - .md\:cu-col-end-13 { + .md\:bui-col-end-13 { grid-column-end: 13; } - .md\:cu-col-end-auto { + .md\:bui-col-end-auto { grid-column-end: auto; } - .md\:cu-row-span-1 { + .md\:bui-row-span-1 { grid-row: span 1 / span 1; } - .md\:cu-row-span-2 { + .md\:bui-row-span-2 { grid-row: span 2 / span 2; } - .md\:cu-row-span-3 { + .md\:bui-row-span-3 { grid-row: span 3 / span 3; } - .md\:cu-row-span-4 { + .md\:bui-row-span-4 { grid-row: span 4 / span 4; } - .md\:cu-row-span-5 { + .md\:bui-row-span-5 { grid-row: span 5 / span 5; } - .md\:cu-row-span-6 { + .md\:bui-row-span-6 { grid-row: span 6 / span 6; } - .md\:cu-row-span-7 { + .md\:bui-row-span-7 { grid-row: span 7 / span 7; } - .md\:cu-row-span-8 { + .md\:bui-row-span-8 { grid-row: span 8 / span 8; } - .md\:cu-row-span-9 { + .md\:bui-row-span-9 { grid-row: span 9 / span 9; } - .md\:cu-row-span-10 { + .md\:bui-row-span-10 { grid-row: span 10 / span 10; } - .md\:cu-row-span-11 { + .md\:bui-row-span-11 { grid-row: span 11 / span 11; } - .md\:cu-row-span-12 { + .md\:bui-row-span-12 { grid-row: span 12 / span 12; } - .md\:cu-row-span-auto { + .md\:bui-row-span-auto { grid-row: span auto / span auto; } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-columns-1 { + .lg\:bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .lg\:cu-columns-2 { + .lg\:bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .lg\:cu-columns-3 { + .lg\:bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .lg\:cu-columns-4 { + .lg\:bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .lg\:cu-columns-5 { + .lg\:bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .lg\:cu-columns-6 { + .lg\:bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } - .lg\:cu-columns-7 { + .lg\:bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } - .lg\:cu-columns-8 { + .lg\:bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } - .lg\:cu-columns-9 { + .lg\:bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } - .lg\:cu-columns-10 { + .lg\:bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } - .lg\:cu-columns-11 { + .lg\:bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } - .lg\:cu-columns-12 { + .lg\:bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } - .lg\:cu-columns-auto { + .lg\:bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } - .lg\:cu-col-span-1 { + .lg\:bui-col-span-1 { grid-column: span 1 / span 1; } - .lg\:cu-col-span-2 { + .lg\:bui-col-span-2 { grid-column: span 2 / span 2; } - .lg\:cu-col-span-3 { + .lg\:bui-col-span-3 { grid-column: span 3 / span 3; } - .lg\:cu-col-span-4 { + .lg\:bui-col-span-4 { grid-column: span 4 / span 4; } - .lg\:cu-col-span-5 { + .lg\:bui-col-span-5 { grid-column: span 5 / span 5; } - .lg\:cu-col-span-6 { + .lg\:bui-col-span-6 { grid-column: span 6 / span 6; } - .lg\:cu-col-span-7 { + .lg\:bui-col-span-7 { grid-column: span 7 / span 7; } - .lg\:cu-col-span-8 { + .lg\:bui-col-span-8 { grid-column: span 8 / span 8; } - .lg\:cu-col-span-9 { + .lg\:bui-col-span-9 { grid-column: span 9 / span 9; } - .lg\:cu-col-span-10 { + .lg\:bui-col-span-10 { grid-column: span 10 / span 10; } - .lg\:cu-col-span-11 { + .lg\:bui-col-span-11 { grid-column: span 11 / span 11; } - .lg\:cu-col-span-12 { + .lg\:bui-col-span-12 { grid-column: span 12 / span 12; } - .lg\:cu-col-span-auto { + .lg\:bui-col-span-auto { grid-column: span auto / span auto; } - .lg\:cu-col-start-1 { + .lg\:bui-col-start-1 { grid-column-start: 1; } - .lg\:cu-col-start-2 { + .lg\:bui-col-start-2 { grid-column-start: 2; } - .lg\:cu-col-start-3 { + .lg\:bui-col-start-3 { grid-column-start: 3; } - .lg\:cu-col-start-4 { + .lg\:bui-col-start-4 { grid-column-start: 4; } - .lg\:cu-col-start-5 { + .lg\:bui-col-start-5 { grid-column-start: 5; } - .lg\:cu-col-start-6 { + .lg\:bui-col-start-6 { grid-column-start: 6; } - .lg\:cu-col-start-7 { + .lg\:bui-col-start-7 { grid-column-start: 7; } - .lg\:cu-col-start-8 { + .lg\:bui-col-start-8 { grid-column-start: 8; } - .lg\:cu-col-start-9 { + .lg\:bui-col-start-9 { grid-column-start: 9; } - .lg\:cu-col-start-10 { + .lg\:bui-col-start-10 { grid-column-start: 10; } - .lg\:cu-col-start-11 { + .lg\:bui-col-start-11 { grid-column-start: 11; } - .lg\:cu-col-start-12 { + .lg\:bui-col-start-12 { grid-column-start: 12; } - .lg\:cu-col-start-13 { + .lg\:bui-col-start-13 { grid-column-start: 13; } - .lg\:cu-col-start-auto { + .lg\:bui-col-start-auto { grid-column-start: auto; } - .lg\:cu-col-end-1 { + .lg\:bui-col-end-1 { grid-column-end: 1; } - .lg\:cu-col-end-2 { + .lg\:bui-col-end-2 { grid-column-end: 2; } - .lg\:cu-col-end-3 { + .lg\:bui-col-end-3 { grid-column-end: 3; } - .lg\:cu-col-end-4 { + .lg\:bui-col-end-4 { grid-column-end: 4; } - .lg\:cu-col-end-5 { + .lg\:bui-col-end-5 { grid-column-end: 5; } - .lg\:cu-col-end-6 { + .lg\:bui-col-end-6 { grid-column-end: 6; } - .lg\:cu-col-end-7 { + .lg\:bui-col-end-7 { grid-column-end: 7; } - .lg\:cu-col-end-8 { + .lg\:bui-col-end-8 { grid-column-end: 8; } - .lg\:cu-col-end-9 { + .lg\:bui-col-end-9 { grid-column-end: 9; } - .lg\:cu-col-end-10 { + .lg\:bui-col-end-10 { grid-column-end: 10; } - .lg\:cu-col-end-11 { + .lg\:bui-col-end-11 { grid-column-end: 11; } - .lg\:cu-col-end-12 { + .lg\:bui-col-end-12 { grid-column-end: 12; } - .lg\:cu-col-end-13 { + .lg\:bui-col-end-13 { grid-column-end: 13; } - .lg\:cu-col-end-auto { + .lg\:bui-col-end-auto { grid-column-end: auto; } - .lg\:cu-row-span-1 { + .lg\:bui-row-span-1 { grid-row: span 1 / span 1; } - .lg\:cu-row-span-2 { + .lg\:bui-row-span-2 { grid-row: span 2 / span 2; } - .lg\:cu-row-span-3 { + .lg\:bui-row-span-3 { grid-row: span 3 / span 3; } - .lg\:cu-row-span-4 { + .lg\:bui-row-span-4 { grid-row: span 4 / span 4; } - .lg\:cu-row-span-5 { + .lg\:bui-row-span-5 { grid-row: span 5 / span 5; } - .lg\:cu-row-span-6 { + .lg\:bui-row-span-6 { grid-row: span 6 / span 6; } - .lg\:cu-row-span-7 { + .lg\:bui-row-span-7 { grid-row: span 7 / span 7; } - .lg\:cu-row-span-8 { + .lg\:bui-row-span-8 { grid-row: span 8 / span 8; } - .lg\:cu-row-span-9 { + .lg\:bui-row-span-9 { grid-row: span 9 / span 9; } - .lg\:cu-row-span-10 { + .lg\:bui-row-span-10 { grid-row: span 10 / span 10; } - .lg\:cu-row-span-11 { + .lg\:bui-row-span-11 { grid-row: span 11 / span 11; } - .lg\:cu-row-span-12 { + .lg\:bui-row-span-12 { grid-row: span 12 / span 12; } - .lg\:cu-row-span-auto { + .lg\:bui-row-span-auto { grid-row: span auto / span auto; } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-columns-1 { + .xl\:bui-columns-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .xl\:cu-columns-2 { + .xl\:bui-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .xl\:cu-columns-3 { + .xl\:bui-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .xl\:cu-columns-4 { + .xl\:bui-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .xl\:cu-columns-5 { + .xl\:bui-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .xl\:cu-columns-6 { + .xl\:bui-columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } - .xl\:cu-columns-7 { + .xl\:bui-columns-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } - .xl\:cu-columns-8 { + .xl\:bui-columns-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } - .xl\:cu-columns-9 { + .xl\:bui-columns-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } - .xl\:cu-columns-10 { + .xl\:bui-columns-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } - .xl\:cu-columns-11 { + .xl\:bui-columns-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } - .xl\:cu-columns-12 { + .xl\:bui-columns-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } - .xl\:cu-columns-auto { + .xl\:bui-columns-auto { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } - .xl\:cu-col-span-1 { + .xl\:bui-col-span-1 { grid-column: span 1 / span 1; } - .xl\:cu-col-span-2 { + .xl\:bui-col-span-2 { grid-column: span 2 / span 2; } - .xl\:cu-col-span-3 { + .xl\:bui-col-span-3 { grid-column: span 3 / span 3; } - .xl\:cu-col-span-4 { + .xl\:bui-col-span-4 { grid-column: span 4 / span 4; } - .xl\:cu-col-span-5 { + .xl\:bui-col-span-5 { grid-column: span 5 / span 5; } - .xl\:cu-col-span-6 { + .xl\:bui-col-span-6 { grid-column: span 6 / span 6; } - .xl\:cu-col-span-7 { + .xl\:bui-col-span-7 { grid-column: span 7 / span 7; } - .xl\:cu-col-span-8 { + .xl\:bui-col-span-8 { grid-column: span 8 / span 8; } - .xl\:cu-col-span-9 { + .xl\:bui-col-span-9 { grid-column: span 9 / span 9; } - .xl\:cu-col-span-10 { + .xl\:bui-col-span-10 { grid-column: span 10 / span 10; } - .xl\:cu-col-span-11 { + .xl\:bui-col-span-11 { grid-column: span 11 / span 11; } - .xl\:cu-col-span-12 { + .xl\:bui-col-span-12 { grid-column: span 12 / span 12; } - .xl\:cu-col-span-auto { + .xl\:bui-col-span-auto { grid-column: span auto / span auto; } - .xl\:cu-col-start-1 { + .xl\:bui-col-start-1 { grid-column-start: 1; } - .xl\:cu-col-start-2 { + .xl\:bui-col-start-2 { grid-column-start: 2; } - .xl\:cu-col-start-3 { + .xl\:bui-col-start-3 { grid-column-start: 3; } - .xl\:cu-col-start-4 { + .xl\:bui-col-start-4 { grid-column-start: 4; } - .xl\:cu-col-start-5 { + .xl\:bui-col-start-5 { grid-column-start: 5; } - .xl\:cu-col-start-6 { + .xl\:bui-col-start-6 { grid-column-start: 6; } - .xl\:cu-col-start-7 { + .xl\:bui-col-start-7 { grid-column-start: 7; } - .xl\:cu-col-start-8 { + .xl\:bui-col-start-8 { grid-column-start: 8; } - .xl\:cu-col-start-9 { + .xl\:bui-col-start-9 { grid-column-start: 9; } - .xl\:cu-col-start-10 { + .xl\:bui-col-start-10 { grid-column-start: 10; } - .xl\:cu-col-start-11 { + .xl\:bui-col-start-11 { grid-column-start: 11; } - .xl\:cu-col-start-12 { + .xl\:bui-col-start-12 { grid-column-start: 12; } - .xl\:cu-col-start-13 { + .xl\:bui-col-start-13 { grid-column-start: 13; } - .xl\:cu-col-start-auto { + .xl\:bui-col-start-auto { grid-column-start: auto; } - .xl\:cu-col-end-1 { + .xl\:bui-col-end-1 { grid-column-end: 1; } - .xl\:cu-col-end-2 { + .xl\:bui-col-end-2 { grid-column-end: 2; } - .xl\:cu-col-end-3 { + .xl\:bui-col-end-3 { grid-column-end: 3; } - .xl\:cu-col-end-4 { + .xl\:bui-col-end-4 { grid-column-end: 4; } - .xl\:cu-col-end-5 { + .xl\:bui-col-end-5 { grid-column-end: 5; } - .xl\:cu-col-end-6 { + .xl\:bui-col-end-6 { grid-column-end: 6; } - .xl\:cu-col-end-7 { + .xl\:bui-col-end-7 { grid-column-end: 7; } - .xl\:cu-col-end-8 { + .xl\:bui-col-end-8 { grid-column-end: 8; } - .xl\:cu-col-end-9 { + .xl\:bui-col-end-9 { grid-column-end: 9; } - .xl\:cu-col-end-10 { + .xl\:bui-col-end-10 { grid-column-end: 10; } - .xl\:cu-col-end-11 { + .xl\:bui-col-end-11 { grid-column-end: 11; } - .xl\:cu-col-end-12 { + .xl\:bui-col-end-12 { grid-column-end: 12; } - .xl\:cu-col-end-13 { + .xl\:bui-col-end-13 { grid-column-end: 13; } - .xl\:cu-col-end-auto { + .xl\:bui-col-end-auto { grid-column-end: auto; } - .xl\:cu-row-span-1 { + .xl\:bui-row-span-1 { grid-row: span 1 / span 1; } - .xl\:cu-row-span-2 { + .xl\:bui-row-span-2 { grid-row: span 2 / span 2; } - .xl\:cu-row-span-3 { + .xl\:bui-row-span-3 { grid-row: span 3 / span 3; } - .xl\:cu-row-span-4 { + .xl\:bui-row-span-4 { grid-row: span 4 / span 4; } - .xl\:cu-row-span-5 { + .xl\:bui-row-span-5 { grid-row: span 5 / span 5; } - .xl\:cu-row-span-6 { + .xl\:bui-row-span-6 { grid-row: span 6 / span 6; } - .xl\:cu-row-span-7 { + .xl\:bui-row-span-7 { grid-row: span 7 / span 7; } - .xl\:cu-row-span-8 { + .xl\:bui-row-span-8 { grid-row: span 8 / span 8; } - .xl\:cu-row-span-9 { + .xl\:bui-row-span-9 { grid-row: span 9 / span 9; } - .xl\:cu-row-span-10 { + .xl\:bui-row-span-10 { grid-row: span 10 / span 10; } - .xl\:cu-row-span-11 { + .xl\:bui-row-span-11 { grid-row: span 11 / span 11; } - .xl\:cu-row-span-12 { + .xl\:bui-row-span-12 { grid-row: span 12 / span 12; } - .xl\:cu-row-span-auto { + .xl\:bui-row-span-auto { grid-row: span auto / span auto; } } diff --git a/packages/canon/src/css/utilities/height.css b/packages/ui/src/css/utilities/height.css similarity index 75% rename from packages/canon/src/css/utilities/height.css rename to packages/ui/src/css/utilities/height.css index 130dfc5020..5c245cbfb9 100644 --- a/packages/canon/src/css/utilities/height.css +++ b/packages/ui/src/css/utilities/height.css @@ -1,86 +1,86 @@ -.cu-h { +.bui-h { height: var(--height); } -.cu-min-h { +.bui-min-h { min-height: var(--min-height); } -.cu-max-h { +.bui-max-h { max-height: var(--max-height); } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-h { + .xs\:bui-h { height: var(--height); } - .xs\:cu-min-h { + .xs\:bui-min-h { min-height: var(--min-height); } - .xs\:cu-max-h { + .xs\:bui-max-h { max-height: var(--max-height); } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-h { + .sm\:bui-h { height: var(--height); } - .sm\:cu-min-h { + .sm\:bui-min-h { min-height: var(--min-height); } - .sm\:cu-max-h { + .sm\:bui-max-h { max-height: var(--max-height); } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-h { + .md\:bui-h { height: var(--height); } - .md\:cu-min-h { + .md\:bui-min-h { min-height: var(--min-height); } - .md\:cu-max-h { + .md\:bui-max-h { max-height: var(--max-height); } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-h { + .lg\:bui-h { height: var(--height); } - .lg\:cu-min-h { + .lg\:bui-min-h { min-height: var(--min-height); } - .lg\:cu-max-h { + .lg\:bui-max-h { max-height: var(--max-height); } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-h { + .xl\:bui-h { height: var(--height); } - .xl\:cu-min-h { + .xl\:bui-min-h { min-height: var(--min-height); } - .xl\:cu-max-h { + .xl\:bui-max-h { max-height: var(--max-height); } } diff --git a/packages/ui/src/css/utilities/m.css b/packages/ui/src/css/utilities/m.css new file mode 100644 index 0000000000..b2c1099d9b --- /dev/null +++ b/packages/ui/src/css/utilities/m.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/mb.css b/packages/ui/src/css/utilities/mb.css new file mode 100644 index 0000000000..576d4d488e --- /dev/null +++ b/packages/ui/src/css/utilities/mb.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-mb { + margin-bottom: var(--pb-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-mb { + margin-bottom: var(--pb-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-mb { + margin-bottom: var(--pb-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-mb { + margin-bottom: var(--pb-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-mb { + margin-bottom: var(--pb-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); + } +} diff --git a/packages/ui/src/css/utilities/ml.css b/packages/ui/src/css/utilities/ml.css new file mode 100644 index 0000000000..b11fe779fb --- /dev/null +++ b/packages/ui/src/css/utilities/ml.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-ml { + margin-left: var(--pl-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-ml { + margin-left: var(--pl-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-ml { + margin-left: var(--pl-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-ml { + margin-left: var(--pl-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-ml { + margin-left: var(--pl-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); + } +} diff --git a/packages/ui/src/css/utilities/mr.css b/packages/ui/src/css/utilities/mr.css new file mode 100644 index 0000000000..215a9dc88d --- /dev/null +++ b/packages/ui/src/css/utilities/mr.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-mr { + margin-right: var(--pr-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-mr { + margin-right: var(--pr-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-mr { + margin-right: var(--pr-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-mr { + margin-right: var(--pr-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-mr { + margin-right: var(--pr-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); + } +} diff --git a/packages/ui/src/css/utilities/mt.css b/packages/ui/src/css/utilities/mt.css new file mode 100644 index 0000000000..30035bf8bd --- /dev/null +++ b/packages/ui/src/css/utilities/mt.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-mt { + margin-top: var(--pt-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-mt { + margin-top: var(--pt-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-mt { + margin-top: var(--pt-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-mt { + margin-top: var(--pt-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-mt { + margin-top: var(--pt-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); + } +} diff --git a/packages/ui/src/css/utilities/mx.css b/packages/ui/src/css/utilities/mx.css new file mode 100644 index 0000000000..36bdf32796 --- /dev/null +++ b/packages/ui/src/css/utilities/mx.css @@ -0,0 +1,524 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-mx { + margin-left: var(--px-xs); + margin-right: var(--px-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-mx { + margin-left: var(--px-sm); + margin-right: var(--px-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-mx { + margin-left: var(--px-md); + margin-right: var(--px-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-mx { + margin-left: var(--px-lg); + margin-right: var(--px-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-mx { + margin-left: var(--px-xl); + margin-right: var(--px-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); + } +} diff --git a/packages/ui/src/css/utilities/my.css b/packages/ui/src/css/utilities/my.css new file mode 100644 index 0000000000..ab3aadf77e --- /dev/null +++ b/packages/ui/src/css/utilities/my.css @@ -0,0 +1,524 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-width: 640px) { + .xs\:bui-my { + margin-top: var(--py-xs); + margin-bottom: var(--py-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); + } +} + +/* Breakpoint sm */ +@media (min-width: 768px) { + .sm\:bui-my { + margin-top: var(--py-sm); + margin-bottom: var(--py-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); + } +} + +/* Breakpoint md */ +@media (min-width: 1024px) { + .md\:bui-my { + margin-top: var(--py-md); + margin-bottom: var(--py-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); + } +} + +/* Breakpoint lg */ +@media (min-width: 1280px) { + .lg\:bui-my { + margin-top: var(--py-lg); + margin-bottom: var(--py-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); + } +} + +/* Breakpoint xl */ +@media (min-width: 1536px) { + .xl\:bui-my { + margin-top: var(--py-xl); + margin-bottom: var(--py-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); + } +} diff --git a/packages/ui/src/css/utilities/p.css b/packages/ui/src/css/utilities/p.css new file mode 100644 index 0000000000..113f10777e --- /dev/null +++ b/packages/ui/src/css/utilities/p.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/pb.css b/packages/ui/src/css/utilities/pb.css new file mode 100644 index 0000000000..bdd3881f86 --- /dev/null +++ b/packages/ui/src/css/utilities/pb.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/pl.css b/packages/ui/src/css/utilities/pl.css new file mode 100644 index 0000000000..07e064293a --- /dev/null +++ b/packages/ui/src/css/utilities/pl.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/canon/src/css/utilities/position.css b/packages/ui/src/css/utilities/position.css similarity index 55% rename from packages/canon/src/css/utilities/position.css rename to packages/ui/src/css/utilities/position.css index 764ada623b..11cc0994b6 100644 --- a/packages/canon/src/css/utilities/position.css +++ b/packages/ui/src/css/utilities/position.css @@ -1,134 +1,134 @@ -.cu-position-absolute { +.bui-position-absolute { position: absolute; } -.cu-position-fixed { +.bui-position-fixed { position: fixed; } -.cu-position-sticky { +.bui-position-sticky { position: sticky; } -.cu-position-relative { +.bui-position-relative { position: relative; } -.cu-position-static { +.bui-position-static { position: static; } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-position-absolute { + .xs\:bui-position-absolute { position: absolute; } - .xs\:cu-position-fixed { + .xs\:bui-position-fixed { position: fixed; } - .xs\:cu-position-sticky { + .xs\:bui-position-sticky { position: sticky; } - .xs\:cu-position-relative { + .xs\:bui-position-relative { position: relative; } - .xs\:cu-position-static { + .xs\:bui-position-static { position: static; } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-position-absolute { + .sm\:bui-position-absolute { position: absolute; } - .sm\:cu-position-fixed { + .sm\:bui-position-fixed { position: fixed; } - .sm\:cu-position-sticky { + .sm\:bui-position-sticky { position: sticky; } - .sm\:cu-position-relative { + .sm\:bui-position-relative { position: relative; } - .sm\:cu-position-static { + .sm\:bui-position-static { position: static; } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-position-absolute { + .md\:bui-position-absolute { position: absolute; } - .md\:cu-position-fixed { + .md\:bui-position-fixed { position: fixed; } - .md\:cu-position-sticky { + .md\:bui-position-sticky { position: sticky; } - .md\:cu-position-relative { + .md\:bui-position-relative { position: relative; } - .md\:cu-position-static { + .md\:bui-position-static { position: static; } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-position-absolute { + .lg\:bui-position-absolute { position: absolute; } - .lg\:cu-position-fixed { + .lg\:bui-position-fixed { position: fixed; } - .lg\:cu-position-sticky { + .lg\:bui-position-sticky { position: sticky; } - .lg\:cu-position-relative { + .lg\:bui-position-relative { position: relative; } - .lg\:cu-position-static { + .lg\:bui-position-static { position: static; } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-position-absolute { + .xl\:bui-position-absolute { position: absolute; } - .xl\:cu-position-fixed { + .xl\:bui-position-fixed { position: fixed; } - .xl\:cu-position-sticky { + .xl\:bui-position-sticky { position: sticky; } - .xl\:cu-position-relative { + .xl\:bui-position-relative { position: relative; } - .xl\:cu-position-static { + .xl\:bui-position-static { position: static; } } diff --git a/packages/ui/src/css/utilities/pr.css b/packages/ui/src/css/utilities/pr.css new file mode 100644 index 0000000000..c6fa94a1c5 --- /dev/null +++ b/packages/ui/src/css/utilities/pr.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/pt.css b/packages/ui/src/css/utilities/pt.css new file mode 100644 index 0000000000..cf557257e3 --- /dev/null +++ b/packages/ui/src/css/utilities/pt.css @@ -0,0 +1,422 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/px.css b/packages/ui/src/css/utilities/px.css new file mode 100644 index 0000000000..37a41d832e --- /dev/null +++ b/packages/ui/src/css/utilities/px.css @@ -0,0 +1,524 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/ui/src/css/utilities/py.css b/packages/ui/src/css/utilities/py.css new file mode 100644 index 0000000000..e3738df00c --- /dev/null +++ b/packages/ui/src/css/utilities/py.css @@ -0,0 +1,524 @@ +.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); +} + +/* Breakpoint xs */ +@media (min-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); + } +} + +/* Breakpoint sm */ +@media (min-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); + } +} + +/* Breakpoint md */ +@media (min-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); + } +} + +/* Breakpoint lg */ +@media (min-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); + } +} + +/* Breakpoint xl */ +@media (min-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); + } +} diff --git a/packages/canon/src/css/utilities/sm.css b/packages/ui/src/css/utilities/sm.css similarity index 52% rename from packages/canon/src/css/utilities/sm.css rename to packages/ui/src/css/utilities/sm.css index 01603f0218..61baaa6b0d 100644 --- a/packages/canon/src/css/utilities/sm.css +++ b/packages/ui/src/css/utilities/sm.css @@ -16,176 +16,176 @@ @layer utilities { @media (min-width: 640px) { - .cu-sm-block { + .bui-sm-block { display: block; } - .cu-sm-border-base { - border-color: var(--canon-border); + .bui-sm-border-base { + border-color: var(--bui-border); border-width: 1px; border-style: solid; } - .cu-sm-border-error { - border-color: var(--canon-border-danger); + .bui-sm-border-error { + border-color: var(--bui-border-danger); border-width: 1px; border-style: solid; } - .cu-sm-border-none { + .bui-sm-border-none { border-color: transparent; border-width: 0; } - .cu-sm-border-selected { - border-color: var(--canon-border-pressed); + .bui-sm-border-selected { + border-color: var(--bui-border-pressed); border-width: 1px; border-style: solid; } - .cu-sm-border-warning { - border-color: var(--canon-border-warning); + .bui-sm-border-warning { + border-color: var(--bui-border-warning); border-width: 1px; border-style: solid; } - .cu-sm-flex { + .bui-sm-flex { display: flex; } - .cu-sm-flex-col { + .bui-sm-flex-col { flex-direction: column; } - .cu-sm-flex-nowrap { + .bui-sm-flex-nowrap { flex-wrap: nowrap; } - .cu-sm-flex-row { + .bui-sm-flex-row { flex-direction: row; } - .cu-sm-flex-wrap { + .bui-sm-flex-wrap { flex-wrap: wrap; } - .cu-sm-flex-wrap-reverse { + .bui-sm-flex-wrap-reverse { flex-wrap: wrap-reverse; } - .cu-sm-gap-2xl { - gap: var(--canon-space-12); + .bui-sm-gap-2xl { + gap: var(--bui-space-12); } - .cu-sm-gap-lg { - gap: var(--canon-space-8); + .bui-sm-gap-lg { + gap: var(--bui-space-8); } - .cu-sm-gap-md { - gap: var(--canon-space-6); + .bui-sm-gap-md { + gap: var(--bui-space-6); } - .cu-sm-gap-none { + .bui-sm-gap-none { gap: 0; } - .cu-sm-gap-sm { - gap: var(--canon-space-4); + .bui-sm-gap-sm { + gap: var(--bui-space-4); } - .cu-sm-gap-xl { - gap: var(--canon-space-10); + .bui-sm-gap-xl { + gap: var(--bui-space-10); } - .cu-sm-gap-xs { - gap: var(--canon-space-3); + .bui-sm-gap-xs { + gap: var(--bui-space-3); } - .cu-sm-hidden { + .bui-sm-hidden { display: none; } - .cu-sm-inline { + .bui-sm-inline { display: inline; } - .cu-sm-inline-block { + .bui-sm-inline-block { display: inline-block; } - .cu-sm-items-center { + .bui-sm-items-center { align-items: center; } - .cu-sm-items-end { + .bui-sm-items-end { align-items: flex-end; } - .cu-sm-items-start { + .bui-sm-items-start { align-items: flex-start; } - .cu-sm-items-stretch { + .bui-sm-items-stretch { align-items: stretch; } - .cu-sm-justify-around { + .bui-sm-justify-around { justify-content: space-around; } - .cu-sm-justify-between { + .bui-sm-justify-between { justify-content: space-between; } - .cu-sm-justify-center { + .bui-sm-justify-center { justify-content: center; } - .cu-sm-justify-end { + .bui-sm-justify-end { justify-content: flex-end; } - .cu-sm-justify-start { + .bui-sm-justify-start { justify-content: flex-start; } - .cu-sm-justify-stretch { + .bui-sm-justify-stretch { justify-content: stretch; } - .cu-sm-rounded-2xl { - border-radius: var(--canon-radius-full); + .bui-sm-rounded-2xl { + border-radius: var(--bui-radius-full); } - .cu-sm-rounded-2xs { - border-radius: var(--canon-radius-1); + .bui-sm-rounded-2xs { + border-radius: var(--bui-radius-1); } - .cu-sm-rounded-lg { - border-radius: var(--canon-radius-5); + .bui-sm-rounded-lg { + border-radius: var(--bui-radius-5); } - .cu-sm-rounded-md { - border-radius: var(--canon-radius-4); + .bui-sm-rounded-md { + border-radius: var(--bui-radius-4); } - .cu-sm-rounded-none { + .bui-sm-rounded-none { border-radius: 0; } - .cu-sm-rounded-sm { - border-radius: var(--canon-radius-3); + .bui-sm-rounded-sm { + border-radius: var(--bui-radius-3); } - .cu-sm-rounded-xl { - border-radius: var(--canon-radius-6); + .bui-sm-rounded-xl { + border-radius: var(--bui-radius-6); } - .cu-sm-rounded-xs { - border-radius: var(--canon-radius-2); + .bui-sm-rounded-xs { + border-radius: var(--bui-radius-2); } - .cu-sm-wrap-reverse { + .bui-sm-wrap-reverse { flex-wrap: wrap-reverse; } } diff --git a/packages/canon/src/css/utilities/width.css b/packages/ui/src/css/utilities/width.css similarity index 74% rename from packages/canon/src/css/utilities/width.css rename to packages/ui/src/css/utilities/width.css index f4f10c9416..6dad08814a 100644 --- a/packages/canon/src/css/utilities/width.css +++ b/packages/ui/src/css/utilities/width.css @@ -1,86 +1,86 @@ -.cu-w { +.bui-w { width: var(--width); } -.cu-min-w { +.bui-min-w { min-width: var(--min-width); } -.cu-max-w { +.bui-max-w { max-width: var(--max-width); } /* Breakpoint xs */ @media (min-width: 640px) { - .xs\:cu-w { + .xs\:bui-w { width: var(--width); } - .xs\:cu-min-w { + .xs\:bui-min-w { min-width: var(--min-width); } - .xs\:cu-max-w { + .xs\:bui-max-w { max-width: var(--max-width); } } /* Breakpoint sm */ @media (min-width: 768px) { - .sm\:cu-w { + .sm\:bui-w { width: var(--width); } - .sm\:cu-min-w { + .sm\:bui-min-w { min-width: var(--min-width); } - .sm\:cu-max-w { + .sm\:bui-max-w { max-width: var(--max-width); } } /* Breakpoint md */ @media (min-width: 1024px) { - .md\:cu-w { + .md\:bui-w { width: var(--width); } - .md\:cu-min-w { + .md\:bui-min-w { min-width: var(--min-width); } - .md\:cu-max-w { + .md\:bui-max-w { max-width: var(--max-width); } } /* Breakpoint lg */ @media (min-width: 1280px) { - .lg\:cu-w { + .lg\:bui-w { width: var(--width); } - .lg\:cu-min-w { + .lg\:bui-min-w { min-width: var(--min-width); } - .lg\:cu-max-w { + .lg\:bui-max-w { max-width: var(--max-width); } } /* Breakpoint xl */ @media (min-width: 1536px) { - .xl\:cu-w { + .xl\:bui-w { width: var(--width); } - .xl\:cu-min-w { + .xl\:bui-min-w { min-width: var(--min-width); } - .xl\:cu-max-w { + .xl\:bui-max-w { max-width: var(--max-width); } } diff --git a/packages/canon/src/css/utilities/xs.css b/packages/ui/src/css/utilities/xs.css similarity index 58% rename from packages/canon/src/css/utilities/xs.css rename to packages/ui/src/css/utilities/xs.css index 5470355fdb..27adb7c7e4 100644 --- a/packages/canon/src/css/utilities/xs.css +++ b/packages/ui/src/css/utilities/xs.css @@ -15,148 +15,148 @@ */ @layer utilities { - .cu-block { + .bui-block { display: block; } - .cu-border-base { - border-color: var(--canon-border); + .bui-border-base { + border-color: var(--bui-border); border-width: 1px; border-style: solid; } - .cu-border-error { - border-color: var(--canon-border-danger); + .bui-border-error { + border-color: var(--bui-border-danger); border-width: 1px; border-style: solid; } - .cu-border-none { + .bui-border-none { border-color: transparent; border-width: 0; } - .cu-border-selected { - border-color: var(--canon-border-pressed); + .bui-border-selected { + border-color: var(--bui-border-pressed); border-width: 1px; border-style: solid; } - .cu-border-warning { - border-color: var(--canon-border-warning); + .bui-border-warning { + border-color: var(--bui-border-warning); border-width: 1px; border-style: solid; } - .cu-flex { + .bui-flex { display: flex; } - .cu-flex-col { + .bui-flex-col { flex-direction: column; } - .cu-flex-nowrap { + .bui-flex-nowrap { flex-wrap: nowrap; } - .cu-flex-row { + .bui-flex-row { flex-direction: row; } - .cu-flex-wrap { + .bui-flex-wrap { flex-wrap: wrap; } - .cu-flex-wrap-reverse { + .bui-flex-wrap-reverse { flex-wrap: wrap-reverse; } - .cu-hidden { + .bui-hidden { display: none; } - .cu-inline { + .bui-inline { display: inline; } - .cu-inline-block { + .bui-inline-block { display: inline-block; } - .cu-items-center { + .bui-items-center { align-items: center; } - .cu-items-end { + .bui-items-end { align-items: flex-end; } - .cu-items-start { + .bui-items-start { align-items: flex-start; } - .cu-items-stretch { + .bui-items-stretch { align-items: stretch; } - .cu-justify-around { + .bui-justify-around { justify-content: space-around; } - .cu-justify-between { + .bui-justify-between { justify-content: space-between; } - .cu-justify-center { + .bui-justify-center { justify-content: center; } - .cu-justify-end { + .bui-justify-end { justify-content: flex-end; } - .cu-justify-start { + .bui-justify-start { justify-content: flex-start; } - .cu-justify-stretch { + .bui-justify-stretch { justify-content: stretch; } - .cu-rounded-2xl { - border-radius: var(--canon-radius-full); + .bui-rounded-2xl { + border-radius: var(--bui-radius-full); } - .cu-rounded-2xs { - border-radius: var(--canon-radius-1); + .bui-rounded-2xs { + border-radius: var(--bui-radius-1); } - .cu-rounded-lg { - border-radius: var(--canon-radius-5); + .bui-rounded-lg { + border-radius: var(--bui-radius-5); } - .cu-rounded-md { - border-radius: var(--canon-radius-4); + .bui-rounded-md { + border-radius: var(--bui-radius-4); } - .cu-rounded-none { + .bui-rounded-none { border-radius: 0; } - .cu-rounded-sm { - border-radius: var(--canon-radius-3); + .bui-rounded-sm { + border-radius: var(--bui-radius-3); } - .cu-rounded-xl { - border-radius: var(--canon-radius-6); + .bui-rounded-xl { + border-radius: var(--bui-radius-6); } - .cu-rounded-xs { - border-radius: var(--canon-radius-2); + .bui-rounded-xs { + border-radius: var(--bui-radius-2); } - .cu-wrap-reverse { + .bui-wrap-reverse { flex-wrap: wrap-reverse; } } diff --git a/packages/canon/src/hooks/useBreakpoint.ts b/packages/ui/src/hooks/useBreakpoint.ts similarity index 100% rename from packages/canon/src/hooks/useBreakpoint.ts rename to packages/ui/src/hooks/useBreakpoint.ts diff --git a/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts b/packages/ui/src/hooks/useIsomorphicLayoutEffect.ts similarity index 100% rename from packages/canon/src/hooks/useIsomorphicLayoutEffect.ts rename to packages/ui/src/hooks/useIsomorphicLayoutEffect.ts diff --git a/packages/canon/src/hooks/useMediaQuery.ts b/packages/ui/src/hooks/useMediaQuery.ts similarity index 100% rename from packages/canon/src/hooks/useMediaQuery.ts rename to packages/ui/src/hooks/useMediaQuery.ts diff --git a/packages/ui/src/hooks/useStyles.ts b/packages/ui/src/hooks/useStyles.ts new file mode 100644 index 0000000000..19f9823236 --- /dev/null +++ b/packages/ui/src/hooks/useStyles.ts @@ -0,0 +1,92 @@ +/* + * 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 { useBreakpoint, breakpoints } from './useBreakpoint'; +import { componentDefinitions } from '../utils/componentDefinitions'; +import type { ComponentDefinitionName, ComponentClassNames } from '../types'; + +/** + * Resolve a responsive value based on the current breakpoint + * @param value - The responsive value (string or object with breakpoint keys) + * @param breakpoint - The current breakpoint + * @returns The resolved value for the current breakpoint + */ +function resolveResponsiveValue( + value: string | Record, + breakpoint: string, +): string | undefined { + if (typeof value === 'string') { + return value; + } + + if (typeof value === 'object' && value !== null) { + const index = breakpoints.findIndex(b => b.id === breakpoint); + + // Look for value at current breakpoint or smaller + for (let i = index; i >= 0; i--) { + if (value[breakpoints[i].id]) { + return value[breakpoints[i].id]; + } + } + + // If no value found, check from smallest breakpoint up + for (let i = 0; i < breakpoints.length; i++) { + if (value[breakpoints[i].id]) { + return value[breakpoints[i].id]; + } + } + } + + return undefined; +} + +/** + * React hook to get class names and data attributes for a component with responsive support + * @param componentName - The name of the component + * @param props - Object with prop values (can be responsive) + * @returns Object with classNames and dataAttributes + */ +export function useStyles( + componentName: T, + props: Record = {}, +): { + classNames: ComponentClassNames; + dataAttributes: Record; + resolvedProps: Record; +} { + const { breakpoint } = useBreakpoint(); + const classNames = componentDefinitions[componentName] + .classNames as ComponentClassNames; + + // Resolve responsive values and generate data attributes + const dataAttributes: Record = {}; + const resolvedProps: Record = {}; + + for (const [key, value] of Object.entries(props)) { + if (value !== undefined && value !== null) { + const resolvedValue = resolveResponsiveValue(value, breakpoint); + if (resolvedValue !== undefined) { + resolvedProps[key] = resolvedValue; + dataAttributes[`data-${key}`] = resolvedValue; + } + } + } + + return { + classNames, + dataAttributes, + resolvedProps, // Also return resolved props for convenience + }; +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts new file mode 100644 index 0000000000..b91d4fc74b --- /dev/null +++ b/packages/ui/src/index.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2024 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. + */ + +/** + * Components used by Backstage plugins and apps + * + * @packageDocumentation + */ + +// Providers +export * from './components/Icon/context'; + +// Layout components +export * from './components/Box'; +export * from './components/Grid'; +export * from './components/Flex'; +export * from './components/Container'; + +// UI components +export * from './components/Avatar'; +export * from './components/Button'; +export * from './components/Card'; +export * from './components/Collapsible'; +export * from './components/DataTable'; +export * from './components/FieldLabel'; +export * from './components/Header'; +export * from './components/HeaderPage'; +export * from './components/Icon'; +export * from './components/ButtonIcon'; +export * from './components/ButtonLink'; +export * from './components/Checkbox'; +export * from './components/RadioGroup'; +export * from './components/Table'; +export * from './components/Tabs'; +export * from './components/Text'; +export * from './components/TextField'; +export * from './components/Tooltip'; +export * from './components/Menu'; +export * from './components/ScrollArea'; +export * from './components/SearchField'; +export * from './components/Link'; +export * from './components/Select'; +export * from './components/Skeleton'; +export * from './components/Switch'; + +// Types +export * from './types'; +export * from './props'; + +// Hooks +export { useBreakpoint } from './hooks/useBreakpoint'; + +// Component Definitions +export * from './utils/componentDefinitions'; diff --git a/packages/canon/src/props/display.props.ts b/packages/ui/src/props/display.props.ts similarity index 97% rename from packages/canon/src/props/display.props.ts rename to packages/ui/src/props/display.props.ts index a71557f05b..4a18aea910 100644 --- a/packages/canon/src/props/display.props.ts +++ b/packages/ui/src/props/display.props.ts @@ -22,7 +22,7 @@ const displayValues = ['none', 'inline', 'inline-block', 'block'] as const; const displayPropDefs = { display: { type: 'enum', - className: 'cu-display', + className: 'bui-display', values: displayValues, responsive: true, }, diff --git a/packages/canon/src/props/gap-props.ts b/packages/ui/src/props/gap-props.ts similarity index 97% rename from packages/canon/src/props/gap-props.ts rename to packages/ui/src/props/gap-props.ts index 68a03a9f51..2701473004 100644 --- a/packages/canon/src/props/gap-props.ts +++ b/packages/ui/src/props/gap-props.ts @@ -21,7 +21,7 @@ import { spacingValues } from './spacing.props'; const gapPropDefs = { gap: { type: 'enum | string', - className: 'cu-gap', + className: 'bui-gap', customProperties: ['--gap'], values: spacingValues, responsive: true, diff --git a/packages/canon/src/props/height.props.ts b/packages/ui/src/props/height.props.ts similarity index 93% rename from packages/canon/src/props/height.props.ts rename to packages/ui/src/props/height.props.ts index b42f965e54..d6195c1fae 100644 --- a/packages/canon/src/props/height.props.ts +++ b/packages/ui/src/props/height.props.ts @@ -19,19 +19,19 @@ import type { PropDef, GetPropDefTypes } from './prop-def'; const heightPropDefs = { height: { type: 'string', - className: 'cu-h', + className: 'bui-h', customProperties: ['--height'], responsive: true, }, minHeight: { type: 'string', - className: 'cu-min-h', + className: 'bui-min-h', customProperties: ['--min-height'], responsive: true, }, maxHeight: { type: 'string', - className: 'cu-max-h', + className: 'bui-max-h', customProperties: ['--max-height'], responsive: true, }, diff --git a/packages/canon/src/props/index.ts b/packages/ui/src/props/index.ts similarity index 100% rename from packages/canon/src/props/index.ts rename to packages/ui/src/props/index.ts diff --git a/packages/canon/src/props/margin.props.ts b/packages/ui/src/props/margin.props.ts similarity index 92% rename from packages/canon/src/props/margin.props.ts rename to packages/ui/src/props/margin.props.ts index 12cb0989e2..31ebf54747 100644 --- a/packages/canon/src/props/margin.props.ts +++ b/packages/ui/src/props/margin.props.ts @@ -21,49 +21,49 @@ const marginPropDefs = (spacingValues: string[]) => m: { type: 'enum | string', values: spacingValues, - className: 'cu-m', + className: 'bui-m', customProperties: ['--m'], responsive: true, }, mx: { type: 'enum | string', values: spacingValues, - className: 'cu-mx', + className: 'bui-mx', customProperties: ['--mx'], responsive: true, }, my: { type: 'enum | string', values: spacingValues, - className: 'cu-my', + className: 'bui-my', customProperties: ['--my'], responsive: true, }, mt: { type: 'enum | string', values: spacingValues, - className: 'cu-mt', + className: 'bui-mt', customProperties: ['--mt'], responsive: true, }, mr: { type: 'enum | string', values: spacingValues, - className: 'cu-mr', + className: 'bui-mr', customProperties: ['--mr'], responsive: true, }, mb: { type: 'enum | string', values: spacingValues, - className: 'cu-mb', + className: 'bui-mb', customProperties: ['--mb'], responsive: true, }, ml: { type: 'enum | string', values: spacingValues, - className: 'cu-ml', + className: 'bui-ml', customProperties: ['--ml'], responsive: true, }, diff --git a/packages/canon/src/props/padding.props.ts b/packages/ui/src/props/padding.props.ts similarity index 92% rename from packages/canon/src/props/padding.props.ts rename to packages/ui/src/props/padding.props.ts index ea42fcd4f1..16d13cf957 100644 --- a/packages/canon/src/props/padding.props.ts +++ b/packages/ui/src/props/padding.props.ts @@ -21,49 +21,49 @@ const paddingPropDefs = (spacingValues: string[]) => ({ p: { type: 'enum | string', - className: 'cu-p', + className: 'bui-p', customProperties: ['--p'], values: spacingValues, responsive: true, }, px: { type: 'enum | string', - className: 'cu-px', + className: 'bui-px', customProperties: ['--px'], values: spacingValues, responsive: true, }, py: { type: 'enum | string', - className: 'cu-py', + className: 'bui-py', customProperties: ['--py'], values: spacingValues, responsive: true, }, pt: { type: 'enum | string', - className: 'cu-pt', + className: 'bui-pt', customProperties: ['--pt'], values: spacingValues, responsive: true, }, pr: { type: 'enum | string', - className: 'cu-pr', + className: 'bui-pr', customProperties: ['--pr'], values: spacingValues, responsive: true, }, pb: { type: 'enum | string', - className: 'cu-pb', + className: 'bui-pb', customProperties: ['--pb'], values: spacingValues, responsive: true, }, pl: { type: 'enum | string', - className: 'cu-pl', + className: 'bui-pl', customProperties: ['--pl'], values: spacingValues, responsive: true, diff --git a/packages/canon/src/props/position.props.ts b/packages/ui/src/props/position.props.ts similarity index 97% rename from packages/canon/src/props/position.props.ts rename to packages/ui/src/props/position.props.ts index 048e3b13ce..027b5e2a63 100644 --- a/packages/canon/src/props/position.props.ts +++ b/packages/ui/src/props/position.props.ts @@ -28,7 +28,7 @@ const positionValues = [ const positionPropDefs = { position: { type: 'enum', - className: 'cu-position', + className: 'bui-position', values: positionValues, responsive: true, }, diff --git a/packages/canon/src/props/prop-def.ts b/packages/ui/src/props/prop-def.ts similarity index 100% rename from packages/canon/src/props/prop-def.ts rename to packages/ui/src/props/prop-def.ts diff --git a/packages/canon/src/props/spacing.props.ts b/packages/ui/src/props/spacing.props.ts similarity index 100% rename from packages/canon/src/props/spacing.props.ts rename to packages/ui/src/props/spacing.props.ts diff --git a/packages/canon/src/props/width.props.ts b/packages/ui/src/props/width.props.ts similarity index 93% rename from packages/canon/src/props/width.props.ts rename to packages/ui/src/props/width.props.ts index fdd8f3fdd4..019ec978ba 100644 --- a/packages/canon/src/props/width.props.ts +++ b/packages/ui/src/props/width.props.ts @@ -19,19 +19,19 @@ import type { GetPropDefTypes, PropDef } from './prop-def'; const widthPropDefs = { width: { type: 'string', - className: 'cu-w', + className: 'bui-w', customProperties: ['--width'], responsive: true, }, minWidth: { type: 'string', - className: 'cu-min-w', + className: 'bui-min-w', customProperties: ['--min-width'], responsive: true, }, maxWidth: { type: 'string', - className: 'cu-max-w', + className: 'bui-max-w', customProperties: ['--max-width'], responsive: true, }, diff --git a/packages/canon/src/types.ts b/packages/ui/src/types.ts similarity index 65% rename from packages/canon/src/types.ts rename to packages/ui/src/types.ts index ee5d954576..d0011bfe8a 100644 --- a/packages/canon/src/types.ts +++ b/packages/ui/src/types.ts @@ -14,24 +14,7 @@ * limitations under the License. */ -/** @public */ -export type AsProps = - | 'div' - | 'span' - | 'p' - | 'article' - | 'section' - | 'main' - | 'nav' - | 'aside' - | 'ul' - | 'ol' - | 'li' - | 'details' - | 'summary' - | 'dd' - | 'dl' - | 'dt'; +import { componentDefinitions } from './utils/componentDefinitions'; /** @public */ export type Breakpoint = 'initial' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'; @@ -115,6 +98,26 @@ export interface SpaceProps { py?: Responsive; } +/** @public */ +export type TextVariants = + | 'title-large' + | 'title-medium' + | 'title-small' + | 'title-x-small' + | 'body-large' + | 'body-medium' + | 'body-small' + | 'body-x-small'; + +/** @public */ +export type TextColors = 'primary' | 'secondary'; + +/** @public */ +export type TextColorStatus = 'danger' | 'warning' | 'success'; + +/** @public */ +export type TextWeights = 'regular' | 'bold'; + /** @public */ export interface UtilityProps extends SpaceProps { alignItems?: Responsive; @@ -131,3 +134,43 @@ export interface UtilityProps extends SpaceProps { justifyContent?: Responsive; rowSpan?: Responsive; } + +/** + * Base type for the component styles structure + * @public + */ +export type ClassNamesMap = Record; + +/** + * Base type for the component styles structure + * @public + */ +export type DataAttributeValues = readonly (string | number | boolean)[]; + +/** + * Base type for the component styles structure + * @public + */ +export type DataAttributesMap = Record; + +/** + * Base type for the component styles structure + * @public + */ +export interface ComponentDefinition { + classNames: ClassNamesMap; + dataAttributes?: DataAttributesMap; +} + +/** + * Type utilities for extracting information from the component styles + * @public + */ +export type ComponentDefinitionName = keyof typeof componentDefinitions; + +/** + * Helper type to extract class names for a component + * @public + */ +export type ComponentClassNames = + (typeof componentDefinitions)[T]['classNames']; diff --git a/packages/ui/src/utils/componentDefinitions.ts b/packages/ui/src/utils/componentDefinitions.ts new file mode 100644 index 0000000000..86aacb7d58 --- /dev/null +++ b/packages/ui/src/utils/componentDefinitions.ts @@ -0,0 +1,291 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ComponentDefinition } from '../types'; + +/** + * Component definitions for the Backstage UI library + * @public + */ +export const componentDefinitions = { + Avatar: { + classNames: { + root: 'bui-AvatarRoot', + image: 'bui-AvatarImage', + fallback: 'bui-AvatarFallback', + }, + dataAttributes: { + size: ['small', 'medium', 'large'] as const, + }, + }, + Box: { + classNames: { + root: 'bui-Box', + }, + }, + Button: { + classNames: { + root: 'bui-Button', + }, + dataAttributes: { + size: ['small', 'medium', 'large'] as const, + variant: ['primary', 'secondary', 'ghost'] as const, + }, + }, + ButtonIcon: { + classNames: { + root: 'bui-ButtonIcon', + }, + }, + ButtonLink: { + classNames: { + root: 'bui-ButtonLink', + }, + }, + Card: { + classNames: { + root: 'bui-Card', + header: 'bui-CardHeader', + body: 'bui-CardBody', + footer: 'bui-CardFooter', + }, + }, + Checkbox: { + classNames: { + root: 'bui-CheckboxRoot', + label: 'bui-CheckboxLabel', + indicator: 'bui-CheckboxIndicator', + }, + dataAttributes: { + checked: [true, false] as const, + }, + }, + Collapsible: { + classNames: { + root: 'bui-CollapsibleRoot', + trigger: 'bui-CollapsibleTrigger', + panel: 'bui-CollapsiblePanel', + }, + }, + Container: { + classNames: { + root: 'bui-Container', + }, + }, + FieldLabel: { + classNames: { + root: 'bui-FieldLabelWrapper', + label: 'bui-FieldLabel', + secondaryLabel: 'bui-FieldSecondaryLabel', + description: 'bui-FieldDescription', + }, + }, + Flex: { + classNames: { + root: 'bui-Flex', + }, + }, + Grid: { + classNames: { + root: 'bui-Grid', + item: 'bui-GridItem', + }, + }, + Header: { + classNames: { + toolbar: 'bui-HeaderToolbar', + toolbarWrapper: 'bui-HeaderToolbarWrapper', + toolbarContent: 'bui-HeaderToolbarContent', + toolbarControls: 'bui-HeaderToolbarControls', + toolbarIcon: 'bui-HeaderToolbarIcon', + toolbarName: 'bui-HeaderToolbarName', + breadcrumbs: 'bui-HeaderBreadcrumbs', + breadcrumb: 'bui-HeaderBreadcrumb', + breadcrumbLink: 'bui-HeaderBreadcrumbLink', + breadcrumbSeparator: 'bui-HeaderBreadcrumbSeparator', + tabsWrapper: 'bui-HeaderTabsWrapper', + }, + }, + HeaderPage: { + classNames: { + root: 'bui-HeaderPage', + content: 'bui-HeaderPageContent', + tabsWrapper: 'bui-HeaderPageTabsWrapper', + controls: 'bui-HeaderPageControls', + }, + }, + Heading: { + classNames: { + root: 'bui-Heading', + }, + dataAttributes: { + variant: ['title1', 'title2', 'title3', 'subtitle'] as const, + color: ['primary', 'secondary', 'muted'] as const, + truncate: [true, false] as const, + }, + }, + Icon: { + classNames: { + root: 'bui-Icon', + }, + }, + Link: { + classNames: { + root: 'bui-Link', + }, + dataAttributes: { + variant: ['subtitle', 'body', 'caption', 'label'] as const, + weight: ['regular', 'bold'] as const, + }, + }, + List: { + classNames: { + root: 'bui-List', + row: 'bui-ListRow', + label: 'bui-ListLabel', + }, + }, + Menu: { + classNames: { + trigger: 'bui-MenuTrigger', + backdrop: 'bui-MenuBackdrop', + positioner: 'bui-MenuPositioner', + popup: 'bui-MenuPopup', + arrow: 'bui-MenuArrow', + item: 'bui-MenuItem', + group: 'bui-MenuGroup', + groupLabel: 'bui-MenuGroupLabel', + radioGroup: 'bui-MenuRadioGroup', + radioItem: 'bui-MenuRadioItem', + radioItemIndicator: 'bui-MenuRadioItemIndicator', + checkboxItem: 'bui-MenuCheckboxItem', + checkboxItemIndicator: 'bui-MenuCheckboxItemIndicator', + submenuTrigger: 'bui-MenuSubmenuTrigger', + separator: 'bui-MenuSeparator', + }, + }, + Popover: { + classNames: { + root: 'bui-Popover', + }, + }, + RadioGroup: { + classNames: { + root: 'bui-RadioGroup', + content: 'bui-RadioGroupContent', + radio: 'bui-Radio', + }, + }, + ScrollArea: { + classNames: { + root: 'bui-ScrollAreaRoot', + viewport: 'bui-ScrollAreaViewport', + scrollbar: 'bui-ScrollAreaScrollbar', + thumb: 'bui-ScrollAreaThumb', + }, + }, + SearchField: { + classNames: { + root: 'bui-SearchField', + clear: 'bui-InputClear', + }, + }, + Select: { + classNames: { + root: 'bui-Select', + trigger: 'bui-SelectTrigger', + value: 'bui-SelectValue', + icon: 'bui-SelectIcon', + list: 'bui-SelectList', + item: 'bui-SelectItem', + itemIndicator: 'bui-SelectItemIndicator', + itemLabel: 'bui-SelectItemLabel', + }, + dataAttributes: { + size: ['small', 'medium'] as const, + }, + }, + Skeleton: { + classNames: { + root: 'bui-Skeleton', + }, + }, + Switch: { + classNames: { + root: 'bui-Switch', + indicator: 'bui-SwitchIndicator', + }, + }, + Table: { + classNames: { + root: 'bui-TableRoot', + header: 'bui-TableHeader', + body: 'bui-TableBody', + row: 'bui-TableRow', + head: 'bui-TableHead', + caption: 'bui-TableCaption', + cell: 'bui-TableCell', + cellText: 'bui-TableCellText', + cellLink: 'bui-TableCellLink', + cellProfile: 'bui-TableCellProfile', + cellProfileAvatar: 'bui-TableCellProfileAvatar', + cellProfileAvatarImage: 'bui-TableCellProfileAvatarImage', + cellProfileAvatarFallback: 'bui-TableCellProfileAvatarFallback', + cellProfileName: 'bui-TableCellProfileName', + cellProfileLink: 'bui-TableCellProfileLink', + }, + }, + Tabs: { + classNames: { + tabs: 'bui-Tabs', + tabList: 'bui-TabList', + tabListWrapper: 'bui-TabListWrapper', + tab: 'bui-Tab', + tabActive: 'bui-TabActive', + tabHovered: 'bui-TabHovered', + panel: 'bui-TabPanel', + }, + }, + Text: { + classNames: { + root: 'bui-Text', + }, + dataAttributes: { + variant: ['subtitle', 'body', 'caption', 'label'] as const, + weight: ['regular', 'bold'] as const, + color: ['primary', 'secondary', 'danger', 'warning', 'success'] as const, + truncate: [true, false] as const, + }, + }, + TextField: { + classNames: { + root: 'bui-TextField', + inputWrapper: 'bui-InputWrapper', + input: 'bui-Input', + inputIcon: 'bui-InputIcon', + }, + dataAttributes: { + invalid: [true, false] as const, + disabled: [true, false] as const, + }, + }, + Tooltip: { + classNames: { + tooltip: 'bui-Tooltip', + arrow: 'bui-TooltipArrow', + }, + }, +} as const satisfies Record; diff --git a/packages/canon/src/utils/extractProps.ts b/packages/ui/src/utils/extractProps.ts similarity index 100% rename from packages/canon/src/utils/extractProps.ts rename to packages/ui/src/utils/extractProps.ts diff --git a/packages/ui/static/CNAME b/packages/ui/static/CNAME new file mode 100644 index 0000000000..21060e506a --- /dev/null +++ b/packages/ui/static/CNAME @@ -0,0 +1 @@ +ui.backstage.io diff --git a/packages/canon/static/favicon.svg b/packages/ui/static/favicon.svg similarity index 100% rename from packages/canon/static/favicon.svg rename to packages/ui/static/favicon.svg diff --git a/packages/canon/static/header.png b/packages/ui/static/header.png similarity index 100% rename from packages/canon/static/header.png rename to packages/ui/static/header.png diff --git a/packages/canon/static/logo.svg b/packages/ui/static/logo.svg similarity index 100% rename from packages/canon/static/logo.svg rename to packages/ui/static/logo.svg diff --git a/packages/yarn-plugin/CHANGELOG.md b/packages/yarn-plugin/CHANGELOG.md index 5f0c845552..9ca9cbdf6f 100644 --- a/packages/yarn-plugin/CHANGELOG.md +++ b/packages/yarn-plugin/CHANGELOG.md @@ -1,5 +1,17 @@ # yarn-plugin-backstage +## 0.0.7 + +### Patch Changes + +- d6084b8: Fixed a bug that would prevent the yarn plugin from installing new dependencies with the `backstage:^` protocol. + +## 0.0.7-next.0 + +### Patch Changes + +- d6084b8: Fixed a bug that would prevent the yarn plugin from installing new dependencies with the `backstage:^` protocol. + ## 0.0.6 ### Patch Changes diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index accf567069..c534c50c76 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -1,6 +1,6 @@ { "name": "yarn-plugin-backstage", - "version": "0.0.6", + "version": "0.0.7", "description": "Yarn plugin for working with Backstage monorepos", "backstage": { "role": "node-library" diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts index ae575a8b02..20cf482cb4 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts @@ -16,18 +16,17 @@ import { Descriptor, DescriptorHash, + httpUtils, IdentHash, Workspace, } from '@yarnpkg/core'; +import { npath, ppath } from '@yarnpkg/fslib'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; -import { getPackageVersion } from '../util'; import { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; - -jest.mock('../util', () => ({ - getPackageVersion: jest.fn(), -})); +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('afterWorkspaceDependencyAddition', () => { + const mockDir = createMockDirectory(); const workspace = { project: { configuration: {}, @@ -35,12 +34,42 @@ describe('afterWorkspaceDependencyAddition', () => { } as Workspace; const target = {} as suggestUtils.Target; const strategies: Array = []; - const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< - typeof getPackageVersion - >; + + const consoleInfoSpy = jest + .spyOn(console, 'info') + .mockImplementation(() => {}); beforeEach(() => { - mockGetPackageVersion.mockReset(); + jest.resetAllMocks(); + + jest.spyOn(httpUtils, 'get').mockResolvedValue({ + releaseVersion: '1.23.45', + packages: [ + { + name: '@backstage/test-package', + version: '6.7.8', + }, + ], + }); + + jest + .spyOn(ppath, 'cwd') + .mockReturnValue(npath.toPortablePath(mockDir.path)); + + jest + .spyOn(process, 'cwd') + .mockReturnValue(npath.toPortablePath(mockDir.path)); + + mockDir.setContent({ + 'backstage.json': JSON.stringify({ + version: '1.23.45', + }), + 'package.json': JSON.stringify({ + workspaces: { + packages: ['packages/*'], + }, + }), + }); }); it('should replace the range for a backstage scoped dependency', async () => { @@ -52,8 +81,6 @@ describe('afterWorkspaceDependencyAddition', () => { identHash: {} as IdentHash, }; - mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); - await afterWorkspaceDependencyAddition( workspace, target, @@ -62,26 +89,20 @@ describe('afterWorkspaceDependencyAddition', () => { ); expect(input.range).toBe('backstage:^'); - expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); - expect(mockGetPackageVersion).toHaveBeenCalledWith( - input, - workspace.project.configuration, + expect(consoleInfoSpy).toHaveBeenCalledWith( + `Setting ${input.scope}/${input.name} to backstage:^`, ); }); it('should not replace the range for a backstage scoped dependency where it cant find a version from remote', async () => { const input: Descriptor = { scope: 'backstage', - name: 'test-package', + name: 'missing-package', range: '^1.0.0', descriptorHash: {} as DescriptorHash, identHash: {} as IdentHash, }; - mockGetPackageVersion.mockImplementation(() => - Promise.reject(new Error('test error')), - ); - await afterWorkspaceDependencyAddition( workspace, target, @@ -90,11 +111,6 @@ describe('afterWorkspaceDependencyAddition', () => { ); expect(input.range).toBe('^1.0.0'); - expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); - expect(mockGetPackageVersion).toHaveBeenCalledWith( - input, - workspace.project.configuration, - ); }); it('should not replace the range for a non-backstage scoped dependency', async () => { @@ -114,6 +130,25 @@ describe('afterWorkspaceDependencyAddition', () => { ); expect(input.range).toBe('^1.0.0'); - expect(mockGetPackageVersion).not.toHaveBeenCalled(); + }); + + it('should not replace the range for a dependency with backstage:^ version', async () => { + const input: Descriptor = { + scope: 'backstage', + name: 'another-test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('backstage:^'); + expect(consoleInfoSpy).not.toHaveBeenCalled(); }); }); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts index 219830a8c9..7fec01b3c7 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts @@ -31,16 +31,18 @@ export const afterWorkspaceDependencyAddition = async ( descriptor.scope === 'backstage' && descriptorRange.protocol !== PROTOCOL ) { + const originalRange = descriptor.range; try { - await getPackageVersion(descriptor, workspace.project.configuration); + descriptor.range = `${PROTOCOL}^`; + await getPackageVersion(descriptor, workspace.project.configuration); // Verify that the actual version can be resolved console.info( `Setting ${descriptor.scope}/${descriptor.name} to ${PROTOCOL}^`, ); - descriptor.range = `${PROTOCOL}^`; } catch (_error: any) { // if there's no found version then this is likely a deprecated package // or otherwise the plugin won't be able to resolve the real version // and we should leave the desired range as is + descriptor.range = originalRange; } } }; diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts index 7bf9c77554..137d91d680 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts @@ -16,30 +16,59 @@ import { Descriptor, DescriptorHash, + httpUtils, IdentHash, Workspace, } from '@yarnpkg/core'; +import { npath, ppath } from '@yarnpkg/fslib'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; -import { getPackageVersion } from '../util'; import { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; - -jest.mock('../util', () => ({ - getPackageVersion: jest.fn(), -})); +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('afterWorkspaceDependencyReplacement.test', () => { + const mockDir = createMockDirectory(); const workspace = { project: { configuration: {}, }, } as Workspace; const target = {} as suggestUtils.Target; - const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< - typeof getPackageVersion - >; + + const consoleWarnSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); beforeEach(() => { - mockGetPackageVersion.mockReset(); + jest.resetAllMocks(); + + jest.spyOn(httpUtils, 'get').mockResolvedValue({ + releaseVersion: '1.23.45', + packages: [ + { + name: '@backstage/test-package', + version: '6.7.8', + }, + ], + }); + + jest + .spyOn(ppath, 'cwd') + .mockReturnValue(npath.toPortablePath(mockDir.path)); + + jest + .spyOn(process, 'cwd') + .mockReturnValue(npath.toPortablePath(mockDir.path)); + + mockDir.setContent({ + 'backstage.json': JSON.stringify({ + version: '1.23.45', + }), + 'package.json': JSON.stringify({ + workspaces: { + packages: ['packages/*'], + }, + }), + }); }); it('should warn that the range is being changed for a backstage scoped dependency', async () => { @@ -58,8 +87,6 @@ describe('afterWorkspaceDependencyReplacement.test', () => { identHash: {} as IdentHash, }; - mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); - await afterWorkspaceDependencyReplacement( workspace, target, @@ -67,46 +94,8 @@ describe('afterWorkspaceDependencyReplacement.test', () => { toDescriptor, ); - expect(toDescriptor.range).toBe('^1.0.0'); - expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); - expect(mockGetPackageVersion).toHaveBeenCalledWith( - toDescriptor, - workspace.project.configuration, - ); - }); - - it('should not warn that the range is being changed for a backstage scoped dependency where it cant find a version from remote', async () => { - const fromDescriptor: Descriptor = { - scope: 'backstage', - name: 'test-package', - range: 'backstage:^', - descriptorHash: {} as DescriptorHash, - identHash: {} as IdentHash, - }; - const toDescriptor: Descriptor = { - scope: 'backstage', - name: 'test-package', - range: '^1.0.0', - descriptorHash: {} as DescriptorHash, - identHash: {} as IdentHash, - }; - - mockGetPackageVersion.mockImplementation(() => - Promise.reject(new Error('test error')), - ); - - await afterWorkspaceDependencyReplacement( - workspace, - target, - fromDescriptor, - toDescriptor, - ); - - expect(toDescriptor.range).toBe('^1.0.0'); - expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); - expect(mockGetPackageVersion).toHaveBeenCalledWith( - toDescriptor, - workspace.project.configuration, + expect(consoleWarnSpy).toHaveBeenCalledWith( + 'test-package should be set to "backstage:^" instead of "^1.0.0". Make sure this change is intentional and not a mistake.', ); }); @@ -132,7 +121,7 @@ describe('afterWorkspaceDependencyReplacement.test', () => { toDescriptor, ); + expect(consoleWarnSpy).not.toHaveBeenCalled(); expect(toDescriptor.range).toBe('^1.0.0'); - expect(mockGetPackageVersion).not.toHaveBeenCalled(); }); }); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts index 55a11086fd..382a19c48b 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts @@ -16,11 +16,10 @@ import { Descriptor, structUtils, Workspace } from '@yarnpkg/core'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; -import { getPackageVersion } from '../util'; import { PROTOCOL } from '../constants'; export const afterWorkspaceDependencyReplacement = async ( - workspace: Workspace, + _workspace: Workspace, _target: suggestUtils.Target, _fromDescriptor: Descriptor, toDescriptor: Descriptor, @@ -31,15 +30,8 @@ export const afterWorkspaceDependencyReplacement = async ( toDescriptor.scope === 'backstage' && toDescriptorRange.protocol !== PROTOCOL ) { - try { - await getPackageVersion(toDescriptor, workspace.project.configuration); - console.warn( - `${toDescriptor.name} should be set to "${PROTOCOL}^" instead of "${toDescriptor.range}". Make sure this change is intentional and not a mistake.`, - ); - } catch (_error: any) { - // if there's no found version then this is likely a deprecated package - // or otherwise the plugin won't be able to resolve the real version - // and we should not warn them. - } + console.warn( + `${toDescriptor.name} should be set to "${PROTOCOL}^" instead of "${toDescriptor.range}". Make sure this change is intentional and not a mistake.`, + ); } }; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 87a8b1020d..c698098c00 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/plugin-api-docs +## 0.12.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/plugin-catalog@1.31.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.12.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-catalog@1.31.1 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + +## 0.12.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-catalog@1.31.1-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.12.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.31.1-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + ## 0.12.8 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8d7e99e781..0a4fd5498f 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.12.8", + "version": "0.12.10-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 14a64c0fca..4fcd285bc3 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-app-backend +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.2 + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-app-node@0.1.35 + - @backstage/plugin-auth-node@0.6.5 + +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.2-next.0 + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-app-node@0.1.35-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.5.3 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 3eede984bd..0198d8eb79 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.3", + "version": "0.5.4", "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 215f6543be..7e0115a8c1 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-app-node +## 0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + +## 0.1.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 0.1.34 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 355bd5b127..d35bdb9cf3 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.34", + "version": "0.1.35", "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 26727d2729..b576215530 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-app-visualizer +## 0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + ## 0.1.20 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 8440070487..189440f566 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.20", + "version": "0.1.21", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index 528736c655..67a5ff0e7e 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-app +## 0.1.11 + +### Patch Changes + +- 09f5e36: Remove trailing slashes in the `AppRoutes` extension to ensure any nested routing behaves correctly. +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-permission-react@0.4.36 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.9-next.0 + - @backstage/theme@0.6.7-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.35 + ## 0.1.10 ### Patch Changes diff --git a/plugins/app/package.json b/plugins/app/package.json index a788a9372a..c741fedaee 100644 --- a/plugins/app/package.json +++ b/plugins/app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app", - "version": "0.1.10", + "version": "0.1.11", "backstage": { "role": "frontend-plugin", "pluginId": "app", diff --git a/plugins/app/src/extensions/AppRoutes.tsx b/plugins/app/src/extensions/AppRoutes.tsx index 304b0b0289..1f15ced3ea 100644 --- a/plugins/app/src/extensions/AppRoutes.tsx +++ b/plugins/app/src/extensions/AppRoutes.tsx @@ -42,7 +42,9 @@ export const AppRoutes = createExtension({ const element = useRoutes([ ...inputs.routes.map(route => ({ - path: `${route.get(coreExtensionData.routePath)}/*`, + path: `${route + .get(coreExtensionData.routePath) + .replace(/\/$/, '')}/*`, element: route.get(coreExtensionData.reactElement), })), { diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 5bd8d12ed7..86ec8013d3 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index b27c995d14..d1b2720870 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.4", + "version": "0.4.5", "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 dfd6475e55..62124b4411 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.4 ### Patch Changes diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 6918506ece..a0dc02b103 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.4", + "version": "0.2.5", "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 b26a474c1e..0bdead75d8 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.25.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-backend@0.25.2-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### 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 ca6fbdd8e2..08f4543411 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.4", + "version": "0.4.5", "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 ca0bd0749c..d4a6024013 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.9 ### 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 7d767f178a..33063c8ae0 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.9", + "version": "0.2.10", "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 ba52bd40a3..04245aeb34 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index e55d5eb81c..d2dd0ffc34 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.4", + "version": "0.3.5", "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 3eb70f352b..74202edec5 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.4 ### 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 4fa29994bb..405ea91a50 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.4", + "version": "0.2.5", "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 adc4bcb53a..10a324946b 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### 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 8da1cf4482..2eb76112ae 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.4", + "version": "0.4.5", "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 4b8cfea2d9..00b7f5e7b0 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### 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 2ce13ba30e..d2413c3f7a 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.4", + "version": "0.4.5", "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 1d446c4ac9..c00f147d37 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 3e97640ca3..55b3b20485 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.4", + "version": "0.3.5", "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 c7466f1ed2..1685db60bd 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index a0951a2089..7a05fb8a15 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.4", + "version": "0.3.5", "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 88123e5154..70898224db 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 417ca82ddc..501a8e9bda 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.4", + "version": "0.3.5", "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 45bac195d6..18ce610ccb 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.9 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index c7c97ac242..33ed6b38e2 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.9", + "version": "0.2.10", "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 0286289724..382b8c4a4b 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index ffe2a45cef..c888038005 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.4", + "version": "0.3.5", "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 4833e43a4d..02a0cf73d9 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index f15e6c68e0..de033eb16d 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.4", + "version": "0.4.5", "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 76c048d5b2..cb2f43bfe5 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.9 ### 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 883cf11f2c..4acb388960 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.9", + "version": "0.2.10", "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 5d524429c6..dea89e79fa 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-auth-backend@0.25.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-backend@0.25.2-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.4.4 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 8f7ebe91be..ca7b46121a 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.4", + "version": "0.4.5", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 073a944e1d..4bc37362cf 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.4 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index c70e1043dd..638ee97c7c 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.4", + "version": "0.2.5", "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 00ae875f18..a167fd592a 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index bf3ccefe98..a0916db92e 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.4", + "version": "0.3.5", "description": "The onelogin-provider 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 2bbf9687cd..d097cdd3db 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 17fec7e87e..2c99a75c46 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.4", + "version": "0.3.5", "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 8b432b873e..7da1a728c3 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.5.4 ### 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 3ee9835ace..93ecfeca1d 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.4", + "version": "0.5.5", "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 bd54646ed6..5f8b05e3b4 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-auth-backend +## 0.25.2 + +### Patch Changes + +- e88cb70: Small internal refactor to move out the `userInfo` database from the `tokenIssuer`. Also removes `exp` from being stored in `UserInfo` and it's now replaced with `created_at` and `updated_at` in the database instead. +- 207778c: Internal refactor of OIDC endpoints and `UserInfoDatabase` +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.25.2-next.1 + +### Patch Changes + +- e88cb70: Small internal refactor to move out the `userInfo` database from the `tokenIssuer`. Also removes `exp` from being stored in `UserInfo` and it's now replaced with `created_at` and `updated_at` in the database instead. +- 207778c: Internal refactor of OIDC endpoints and `UserInfoDatabase` + +## 0.25.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + ## 0.25.1 ### Patch Changes diff --git a/plugins/auth-backend/migrations/20250707164600_user_created_at.js b/plugins/auth-backend/migrations/20250707164600_user_created_at.js new file mode 100644 index 0000000000..eb78cb21b0 --- /dev/null +++ b/plugins/auth-backend/migrations/20250707164600_user_created_at.js @@ -0,0 +1,37 @@ +/* + * Copyright 2024 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. + */ + +// @ts-check + +/** + * @param {import('knex').Knex} knex + */ +exports.up = async function up(knex) { + await knex.schema.alterTable('user_info', table => { + table.renameColumn('exp', 'updated_at'); + table.timestamp('created_at').notNullable().defaultTo(knex.fn.now()); + }); +}; + +/** + * @param {import('knex').Knex} knex + */ +exports.down = async function down(knex) { + await knex.schema.alterTable('user_info', table => { + table.dropColumn('created_at'); + table.renameColumn('updated_at', 'exp'); + }); +}; diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 925469b7ea..a477973262 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.1", + "version": "0.25.2", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-backend/report.sql.md b/plugins/auth-backend/report.sql.md index 7eef7a33cb..b135414af6 100644 --- a/plugins/auth-backend/report.sql.md +++ b/plugins/auth-backend/report.sql.md @@ -33,11 +33,12 @@ ## Table `user_info` -| Column | Type | Nullable | Max Length | Default | -| ----------------- | -------------------------- | -------- | ---------- | ------- | -| `exp` | `timestamp with time zone` | false | - | - | -| `user_entity_ref` | `character varying` | false | 255 | - | -| `user_info` | `text` | false | - | - | +| Column | Type | Nullable | Max Length | Default | +| ----------------- | -------------------------- | -------- | ---------- | ------------------- | +| `created_at` | `timestamp with time zone` | false | - | `CURRENT_TIMESTAMP` | +| `updated_at` | `timestamp with time zone` | false | - | - | +| `user_entity_ref` | `character varying` | false | 255 | - | +| `user_info` | `text` | false | - | - | ### Indices diff --git a/plugins/auth-backend/src/authPlugin.test.ts b/plugins/auth-backend/src/authPlugin.test.ts index cd2b558c80..65d44614fe 100644 --- a/plugins/auth-backend/src/authPlugin.test.ts +++ b/plugins/auth-backend/src/authPlugin.test.ts @@ -86,6 +86,7 @@ describe('authPlugin', () => { }); const refreshRes = await request(server).post('/api/auth/guest/refresh'); + expect(refreshRes.status).toBe(200); expect(refreshRes.body).toMatchObject({ backstageIdentity: { @@ -110,7 +111,6 @@ describe('authPlugin', () => { claims: { sub: expectedIdentity.userEntityRef, ent: expectedIdentity.ownershipEntityRefs, - exp: expect.any(Number), }, }); }); @@ -160,7 +160,6 @@ describe('authPlugin', () => { claims: { sub: expectedIdentity.userEntityRef, ent: expectedIdentity.ownershipEntityRefs, - exp: expect.any(Number), }, }); }); diff --git a/plugins/auth-backend/src/identity/UserInfoDatabaseHandler.test.ts b/plugins/auth-backend/src/database/UserInfoDatabase.test.ts similarity index 83% rename from plugins/auth-backend/src/identity/UserInfoDatabaseHandler.test.ts rename to plugins/auth-backend/src/database/UserInfoDatabase.test.ts index 4d696aa8f2..edaeec450b 100644 --- a/plugins/auth-backend/src/identity/UserInfoDatabaseHandler.test.ts +++ b/plugins/auth-backend/src/database/UserInfoDatabase.test.ts @@ -17,7 +17,9 @@ import { resolvePackagePath } from '@backstage/backend-plugin-api'; import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; import { Knex } from 'knex'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; +import { UserInfoDatabase } from './UserInfoDatabase'; +import { AuthDatabase } from './AuthDatabase'; +import { DateTime } from 'luxon'; const migrationsDir = resolvePackagePath( '@backstage/plugin-auth-backend', @@ -26,7 +28,7 @@ const migrationsDir = resolvePackagePath( jest.setTimeout(60_000); -describe('UserInfoDatabaseHandler', () => { +describe('UserInfoDatabase', () => { const databases = TestDatabases.create(); async function createDatabaseHandler(databaseId: TestDatabaseId) { @@ -38,7 +40,11 @@ describe('UserInfoDatabaseHandler', () => { return { knex, - dbHandler: new UserInfoDatabaseHandler(knex), + dbHandler: await UserInfoDatabase.create({ + database: AuthDatabase.create({ + getClient: async () => knex, + }), + }), }; } @@ -46,7 +52,7 @@ describe('UserInfoDatabaseHandler', () => { 'should support database %p', databaseId => { let knex: Knex; - let dbHandler: UserInfoDatabaseHandler; + let dbHandler: UserInfoDatabase; beforeEach(async () => { ({ knex, dbHandler } = await createDatabaseHandler(databaseId)); @@ -57,7 +63,6 @@ describe('UserInfoDatabaseHandler', () => { claims: { sub: 'user:default/foo', ent: ['group:default/foo-group', 'group:default/bar'], - exp: 1234567890, }, }; @@ -66,10 +71,12 @@ describe('UserInfoDatabaseHandler', () => { const savedUserInfo = await knex('user_info') .where('user_entity_ref', 'user:default/foo') .first(); + expect(savedUserInfo).toEqual({ user_entity_ref: 'user:default/foo', user_info: JSON.stringify(userInfo), - exp: expect.anything(), + updated_at: expect.anything(), + created_at: expect.anything(), }); userInfo.claims.ent = ['group:default/group1', 'group:default/group2']; @@ -78,10 +85,12 @@ describe('UserInfoDatabaseHandler', () => { const updatedUserInfo = await knex('user_info') .where('user_entity_ref', 'user:default/foo') .first(); + expect(updatedUserInfo).toEqual({ user_entity_ref: 'user:default/foo', user_info: JSON.stringify(userInfo), - exp: expect.anything(), + updated_at: expect.anything(), + created_at: expect.anything(), }); }); @@ -90,14 +99,13 @@ describe('UserInfoDatabaseHandler', () => { claims: { sub: 'user:default/backstage-user', ent: ['group:default/group1', 'group:default/group2'], - exp: 1234567890, }, }; await knex('user_info').insert({ user_entity_ref: 'user:default/backstage-user', user_info: JSON.stringify(userInfo), - exp: knex.fn.now(), + updated_at: DateTime.now().toSQL({ includeOffset: false }), }); const savedUserInfo = await dbHandler.getUserInfo( diff --git a/plugins/auth-backend/src/identity/UserInfoDatabaseHandler.ts b/plugins/auth-backend/src/database/UserInfoDatabase.ts similarity index 75% rename from plugins/auth-backend/src/identity/UserInfoDatabaseHandler.ts rename to plugins/auth-backend/src/database/UserInfoDatabase.ts index c0b31de8e4..9377ab89f7 100644 --- a/plugins/auth-backend/src/identity/UserInfoDatabaseHandler.ts +++ b/plugins/auth-backend/src/database/UserInfoDatabase.ts @@ -17,31 +17,30 @@ import { DateTime } from 'luxon'; import { Knex } from 'knex'; -import { BackstageTokenPayload } from './TokenFactory'; +import { AuthDatabase } from './AuthDatabase'; +import { JsonObject } from '@backstage/types'; const TABLE = 'user_info'; type Row = { user_entity_ref: string; user_info: string; - exp: string; + updated_at: string; }; type UserInfo = { - claims: Omit; + claims: JsonObject; }; -export class UserInfoDatabaseHandler { - constructor(private readonly client: Knex) {} +export class UserInfoDatabase { + private constructor(private readonly client: Knex) {} async addUserInfo(userInfo: UserInfo): Promise { await this.client(TABLE) .insert({ user_entity_ref: userInfo.claims.sub as string, user_info: JSON.stringify(userInfo), - exp: DateTime.fromSeconds(userInfo.claims.exp as number, { - zone: 'utc', - }).toSQL({ includeOffset: false }), + updated_at: DateTime.utc().toSQL({ includeOffset: false }), }) .onConflict('user_entity_ref') .merge(); @@ -59,4 +58,9 @@ export class UserInfoDatabaseHandler { const userInfo = JSON.parse(info.user_info); return userInfo; } + + static async create(options: { database: AuthDatabase }) { + const client = await options.database.get(); + return new UserInfoDatabase(client); + } } diff --git a/plugins/auth-backend/src/identity/StaticTokenIssuer.test.ts b/plugins/auth-backend/src/identity/StaticTokenIssuer.test.ts index ef6f7bd148..ad08427e85 100644 --- a/plugins/auth-backend/src/identity/StaticTokenIssuer.test.ts +++ b/plugins/auth-backend/src/identity/StaticTokenIssuer.test.ts @@ -18,8 +18,6 @@ import { createLocalJWKSet, jwtVerify } from 'jose'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { StaticKeyStore } from './StaticKeyStore'; import { mockServices } from '@backstage/backend-test-utils'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; -import { omit } from 'lodash'; const logger = mockServices.logger.mock(); const entityRef = stringifyEntityRef({ @@ -29,10 +27,6 @@ const entityRef = stringifyEntityRef({ }); describe('StaticTokenIssuer', () => { - const mockUserInfoDatabaseHandler = { - addUserInfo: jest.fn().mockResolvedValue(undefined), - } as unknown as UserInfoDatabaseHandler; - const staticKeyStore = { listKeys: () => { return Promise.resolve({ @@ -85,7 +79,6 @@ describe('StaticTokenIssuer', () => { logger, issuer: 'my-issuer', sessionExpirationSeconds: keyDurationSeconds, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }, staticKeyStore as unknown as StaticKeyStore, ); @@ -119,9 +112,6 @@ describe('StaticTokenIssuer', () => { expect(verifyResult.payload.exp).toBe( verifyResult.payload.iat! + keyDurationSeconds, ); - expect(mockUserInfoDatabaseHandler.addUserInfo).toHaveBeenCalledWith({ - claims: omit(verifyResult.payload, ['aud', 'iat', 'iss', 'uip']), - }); }); it('should issue valid tokens with omitted claims', async () => { @@ -131,7 +121,6 @@ describe('StaticTokenIssuer', () => { logger, issuer: 'my-issuer', sessionExpirationSeconds: keyDurationSeconds, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, omitClaimsFromToken: ['ent'], }, staticKeyStore as unknown as StaticKeyStore, @@ -165,11 +154,5 @@ describe('StaticTokenIssuer', () => { expect(verifyResult.payload.exp).toBe( verifyResult.payload.iat! + keyDurationSeconds, ); - expect(mockUserInfoDatabaseHandler.addUserInfo).toHaveBeenCalledWith({ - claims: { - ...omit(verifyResult.payload, ['aud', 'iat', 'iss', 'uip']), - ent: [entityRef], - }, - }); }); }); diff --git a/plugins/auth-backend/src/identity/StaticTokenIssuer.ts b/plugins/auth-backend/src/identity/StaticTokenIssuer.ts index 6875e47457..965eb5164c 100644 --- a/plugins/auth-backend/src/identity/StaticTokenIssuer.ts +++ b/plugins/auth-backend/src/identity/StaticTokenIssuer.ts @@ -22,7 +22,6 @@ import { BackstageSignInResult, TokenParams, } from '@backstage/plugin-auth-node'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; import { issueUserToken } from './issueUserToken'; export type Config = { @@ -42,7 +41,6 @@ export type Options = { * A list of claims to omit from issued tokens and only store in the user info database */ omitClaimsFromToken?: string[]; - userInfoDatabaseHandler: UserInfoDatabaseHandler; }; /** @@ -55,7 +53,6 @@ export class StaticTokenIssuer implements TokenIssuer { private readonly keyStore: StaticKeyStore; private readonly sessionExpirationSeconds: number; private readonly omitClaimsFromToken?: string[]; - private readonly userInfoDatabaseHandler: UserInfoDatabaseHandler; public constructor(options: Options, keyStore: StaticKeyStore) { this.issuer = options.issuer; @@ -63,10 +60,11 @@ export class StaticTokenIssuer implements TokenIssuer { this.sessionExpirationSeconds = options.sessionExpirationSeconds; this.keyStore = keyStore; this.omitClaimsFromToken = options.omitClaimsFromToken; - this.userInfoDatabaseHandler = options.userInfoDatabaseHandler; } - public async issueToken(params: TokenParams): Promise { + public async issueToken( + params: TokenParams & { claims: { ent: string[] } }, + ): Promise { const key = await this.getSigningKey(); return issueUserToken({ @@ -76,7 +74,6 @@ export class StaticTokenIssuer implements TokenIssuer { logger: this.logger, omitClaimsFromToken: this.omitClaimsFromToken, params, - userInfoDatabaseHandler: this.userInfoDatabaseHandler, }); } diff --git a/plugins/auth-backend/src/identity/TokenFactory.test.ts b/plugins/auth-backend/src/identity/TokenFactory.test.ts index 764b26eda4..e6cd888be6 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.test.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.test.ts @@ -21,10 +21,8 @@ import { decodeProtectedHeader, jwtVerify, } from 'jose'; -import { omit } from 'lodash'; import { MemoryKeyStore } from './MemoryKeyStore'; import { TokenFactory } from './TokenFactory'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; import { tokenTypes } from '@backstage/plugin-auth-node'; import { mockServices } from '@backstage/backend-test-utils'; @@ -45,10 +43,6 @@ const entityRef = stringifyEntityRef({ }); describe('TokenFactory', () => { - const mockUserInfoDatabaseHandler = { - addUserInfo: jest.fn().mockResolvedValue(undefined), - } as unknown as UserInfoDatabaseHandler; - it('should issue valid tokens signed by a listed key', async () => { const keyDurationSeconds = 5; const factory = new TokenFactory({ @@ -56,7 +50,6 @@ describe('TokenFactory', () => { keyStore: new MemoryKeyStore(), keyDurationSeconds, logger, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); await expect(factory.listPublicKeys()).resolves.toEqual({ keys: [] }); @@ -93,10 +86,6 @@ describe('TokenFactory', () => { verifyResult.payload.iat! + keyDurationSeconds, ); - expect(mockUserInfoDatabaseHandler.addUserInfo).toHaveBeenCalledWith({ - claims: omit(verifyResult.payload, ['aud', 'iat', 'iss', 'uip']), - }); - // Emulate the reconstruction of a limited user token const limitedUserToken = [ base64url.encode( @@ -139,14 +128,13 @@ describe('TokenFactory', () => { keyStore: new MemoryKeyStore(), keyDurationSeconds: 5, logger, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); const { token: token1 } = await factory.issueToken({ - claims: { sub: entityRef }, + claims: { sub: entityRef, ent: [entityRef] }, }); const { token: token2 } = await factory.issueToken({ - claims: { sub: entityRef }, + claims: { sub: entityRef, ent: [entityRef] }, }); expect(jwtKid(token1)).toBe(jwtKid(token2)); @@ -165,7 +153,7 @@ describe('TokenFactory', () => { }); const { token: token3 } = await factory.issueToken({ - claims: { sub: entityRef }, + claims: { sub: entityRef, ent: [entityRef] }, }); expect(jwtKid(token3)).not.toBe(jwtKid(token2)); @@ -185,12 +173,11 @@ describe('TokenFactory', () => { keyStore: new MemoryKeyStore(), keyDurationSeconds, logger, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); await expect(() => { return factory.issueToken({ - claims: { sub: 'UserId' }, + claims: { sub: 'UserId', ent: [entityRef] }, }); }).rejects.toThrow(); }); @@ -203,12 +190,11 @@ describe('TokenFactory', () => { keyDurationSeconds, logger, algorithm: '', - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); await expect(() => { return factory.issueToken({ - claims: { sub: 'UserId' }, + claims: { sub: 'UserId', ent: [entityRef] }, }); }).rejects.toThrow(); }); @@ -219,7 +205,6 @@ describe('TokenFactory', () => { keyStore: new MemoryKeyStore(), keyDurationSeconds: 5, logger, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); await expect(() => { @@ -238,7 +223,6 @@ describe('TokenFactory', () => { keyStore: new MemoryKeyStore(), keyDurationSeconds, logger, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, }); const { token } = await factory.issueToken({ diff --git a/plugins/auth-backend/src/identity/TokenFactory.ts b/plugins/auth-backend/src/identity/TokenFactory.ts index 5a8a789d17..d94825e322 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.ts @@ -25,7 +25,6 @@ import { } from '@backstage/plugin-auth-node'; import { AnyJWK, KeyStore, TokenIssuer } from './types'; import { JsonValue } from '@backstage/types'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; import { issueUserToken } from './issueUserToken'; /** @@ -92,7 +91,6 @@ type Options = { * A list of claims to omit from issued tokens and only store in the user info database */ omitClaimsFromToken?: string[]; - userInfoDatabaseHandler: UserInfoDatabaseHandler; }; /** @@ -116,7 +114,6 @@ export class TokenFactory implements TokenIssuer { private readonly keyDurationSeconds: number; private readonly algorithm: string; private readonly omitClaimsFromToken?: string[]; - private readonly userInfoDatabaseHandler: UserInfoDatabaseHandler; private keyExpiry?: Date; private privateKeyPromise?: Promise; @@ -128,10 +125,11 @@ export class TokenFactory implements TokenIssuer { this.keyDurationSeconds = options.keyDurationSeconds; this.algorithm = options.algorithm ?? 'ES256'; this.omitClaimsFromToken = options.omitClaimsFromToken; - this.userInfoDatabaseHandler = options.userInfoDatabaseHandler; } - async issueToken(params: TokenParams): Promise { + async issueToken( + params: TokenParams & { claims: { ent: string[] } }, + ): Promise { const key = await this.getKey(); return issueUserToken({ @@ -141,7 +139,6 @@ export class TokenFactory implements TokenIssuer { logger: this.logger, omitClaimsFromToken: this.omitClaimsFromToken, params, - userInfoDatabaseHandler: this.userInfoDatabaseHandler, }); } diff --git a/plugins/auth-backend/src/identity/issueUserToken.ts b/plugins/auth-backend/src/identity/issueUserToken.ts index d411439e6e..8deeb96cc3 100644 --- a/plugins/auth-backend/src/identity/issueUserToken.ts +++ b/plugins/auth-backend/src/identity/issueUserToken.ts @@ -22,7 +22,6 @@ import { tokenTypes, } from '@backstage/plugin-auth-node'; import { omit } from 'lodash'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; import { LoggerService } from '@backstage/backend-plugin-api'; import { GeneralSign, importJWK, JWK, KeyLike, SignJWT } from 'jose'; import { BackstageTokenPayload } from './TokenFactory'; @@ -37,17 +36,15 @@ export async function issueUserToken({ logger, omitClaimsFromToken, params, - userInfoDatabaseHandler, }: { issuer: string; key: JWK; keyDurationSeconds: number; logger: LoggerService; omitClaimsFromToken?: string[]; - params: TokenParams; - userInfoDatabaseHandler: UserInfoDatabaseHandler; + params: TokenParams & { claims: { ent: string[] } }; }): Promise { - const { sub, ent = [sub], ...additionalClaims } = params.claims; + const { sub, ent, ...additionalClaims } = params.claims; const aud = tokenTypes.user.audClaim; const iat = Math.floor(Date.now() / MS_IN_S); const exp = iat + keyDurationSeconds; @@ -109,12 +106,6 @@ export async function issueUserToken({ ); } - // Store the user info in the database upon successful token - // issuance so that it can be retrieved later by limited user tokens - await userInfoDatabaseHandler.addUserInfo({ - claims: omit(claims, ['aud', 'iat', 'iss', 'uip']), - }); - return { token, identity: { diff --git a/plugins/auth-backend/src/identity/router.test.ts b/plugins/auth-backend/src/identity/router.test.ts deleted file mode 100644 index 9ede44f195..0000000000 --- a/plugins/auth-backend/src/identity/router.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - coreServices, - createBackendPlugin, -} from '@backstage/backend-plugin-api'; -import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; -import Router from 'express-promise-router'; -import request from 'supertest'; -import { bindOidcRouter } from './router'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; - -describe('bindOidcRouter', () => { - it('should return user info for full tokens', async () => { - const auth = mockServices.auth.mock(); - const mockUserInfoDatabaseHandler = { - getUserInfo: jest.fn().mockResolvedValue({ - claims: { - sub: 'k/ns:n', - ent: ['k/ns:a', 'k/ns:b'], - }, - }), - } as unknown as UserInfoDatabaseHandler; - - const { server } = await startTestBackend({ - features: [ - createBackendPlugin({ - pluginId: 'auth', - register(reg) { - reg.registerInit({ - deps: { httpRouter: coreServices.httpRouter }, - async init({ httpRouter }) { - const router = Router(); - bindOidcRouter(router, { - baseUrl: 'http://localhost:7000', - auth, - tokenIssuer: {} as any, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, - }); - httpRouter.use(router); - httpRouter.addAuthPolicy({ - path: '/', - allow: 'unauthenticated', - }); - }, - }); - }, - }), - ], - }); - - auth.authenticate.mockResolvedValueOnce({} as any); - auth.isPrincipal.mockReturnValueOnce(true); - - await request(server) - .get('/api/auth/v1/userinfo') - .set( - 'Authorization', - `Bearer h.${btoa( - JSON.stringify({ sub: 'k/ns:n', ent: ['k/ns:a', 'k/ns:b'] }), - )}.s`, - ) - .expect(200, { - claims: { - sub: 'k/ns:n', - ent: ['k/ns:a', 'k/ns:b'], - }, - }); - - expect(mockUserInfoDatabaseHandler.getUserInfo).toHaveBeenCalledWith( - 'k/ns:n', - ); - }); - - it('should return user info for limited tokens', async () => { - const auth = mockServices.auth.mock(); - const mockUserInfoDatabaseHandler = { - getUserInfo: jest.fn().mockResolvedValue({ - claims: { - sub: 'k/ns:n', - ent: ['k/ns:a', 'k/ns:b'], - }, - }), - } as unknown as UserInfoDatabaseHandler; - - const { server } = await startTestBackend({ - features: [ - createBackendPlugin({ - pluginId: 'auth', - register(reg) { - reg.registerInit({ - deps: { httpRouter: coreServices.httpRouter }, - async init({ httpRouter }) { - const router = Router(); - bindOidcRouter(router, { - baseUrl: 'http://localhost:7000', - auth, - tokenIssuer: {} as any, - userInfoDatabaseHandler: mockUserInfoDatabaseHandler, - }); - httpRouter.use(router); - httpRouter.addAuthPolicy({ - path: '/', - allow: 'unauthenticated', - }); - }, - }); - }, - }), - ], - }); - - auth.authenticate.mockResolvedValueOnce({} as any); - auth.isPrincipal.mockReturnValueOnce(true); - - await request(server) - .get('/api/auth/v1/userinfo') - .set( - 'Authorization', - `Bearer h.${btoa(JSON.stringify({ sub: 'k/ns:n' }))}.s`, - ) - .expect(200, { - claims: { - sub: 'k/ns:n', - ent: ['k/ns:a', 'k/ns:b'], - }, - }); - - expect(mockUserInfoDatabaseHandler.getUserInfo).toHaveBeenCalledWith( - 'k/ns:n', - ); - }); -}); diff --git a/plugins/auth-backend/src/identity/router.ts b/plugins/auth-backend/src/identity/router.ts deleted file mode 100644 index 3952ec64b5..0000000000 --- a/plugins/auth-backend/src/identity/router.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import express from 'express'; -import Router from 'express-promise-router'; -import { TokenIssuer } from './types'; -import { AuthService } from '@backstage/backend-plugin-api'; -import { decodeJwt } from 'jose'; -import { AuthenticationError, InputError } from '@backstage/errors'; -import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler'; - -export function bindOidcRouter( - targetRouter: express.Router, - options: { - baseUrl: string; - auth: AuthService; - tokenIssuer: TokenIssuer; - userInfoDatabaseHandler: UserInfoDatabaseHandler; - }, -) { - const { baseUrl, auth, tokenIssuer, userInfoDatabaseHandler } = options; - - const router = Router(); - targetRouter.use(router); - - const config = { - issuer: baseUrl, - token_endpoint: `${baseUrl}/v1/token`, - userinfo_endpoint: `${baseUrl}/v1/userinfo`, - jwks_uri: `${baseUrl}/.well-known/jwks.json`, - response_types_supported: ['id_token'], - subject_types_supported: ['public'], - id_token_signing_alg_values_supported: [ - 'RS256', - 'RS384', - 'RS512', - 'ES256', - 'ES384', - 'ES512', - 'PS256', - 'PS384', - 'PS512', - 'EdDSA', - ], - scopes_supported: ['openid'], - token_endpoint_auth_methods_supported: [], - claims_supported: ['sub', 'ent'], - grant_types_supported: [], - }; - - router.get('/.well-known/openid-configuration', (_req, res) => { - res.json(config); - }); - - router.get('/.well-known/jwks.json', async (_req, res) => { - const { keys } = await tokenIssuer.listPublicKeys(); - res.json({ keys }); - }); - - router.get('/v1/token', (_req, res) => { - res.status(501).send('Not Implemented'); - }); - - // This endpoint doesn't use the regular HttpAuthService, since the contract - // is specifically for the header to be communicated in the Authorization - // header, regardless of token type - router.get('/v1/userinfo', async (req, res) => { - const matches = req.headers.authorization?.match(/^Bearer[ ]+(\S+)$/i); - const token = matches?.[1]; - if (!token) { - throw new AuthenticationError('No token provided'); - } - - const credentials = await auth.authenticate(token, { - allowLimitedAccess: true, - }); - if (!auth.isPrincipal(credentials, 'user')) { - throw new InputError( - 'Userinfo endpoint must be called with a token that represents a user principal', - ); - } - - const { sub: userEntityRef } = decodeJwt(token); - - if (typeof userEntityRef !== 'string') { - throw new Error('Invalid user token, user entity ref must be a string'); - } - - const userInfo = await userInfoDatabaseHandler.getUserInfo(userEntityRef); - if (!userInfo) { - res.status(404).send('User info not found'); - return; - } - - res.json(userInfo); - }); -} diff --git a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.test.ts b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.test.ts index 4426cb7815..d0323e7651 100644 --- a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.test.ts +++ b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.test.ts @@ -19,6 +19,7 @@ import { mockServices } from '@backstage/backend-test-utils'; import { TokenIssuer } from '../../identity/types'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; import { NotFoundError } from '@backstage/errors'; +import { UserInfoDatabase } from '../../database/UserInfoDatabase'; describe('CatalogAuthResolverContext', () => { beforeEach(() => { @@ -28,6 +29,16 @@ describe('CatalogAuthResolverContext', () => { const catalog = catalogServiceMock(); jest.spyOn(catalog, 'getEntities'); + const mockUserInfo = { + addUserInfo: jest.fn().mockResolvedValue(undefined), + getUserInfo: jest.fn().mockResolvedValue({ + claims: { + sub: 'user:default/user', + ent: ['user:default/user'], + }, + }), + } as unknown as jest.Mocked; + it('adds kind to filter when missing', async () => { const auth = mockServices.auth(); const context = CatalogAuthResolverContext.create({ @@ -35,6 +46,7 @@ describe('CatalogAuthResolverContext', () => { catalog, tokenIssuer: {} as TokenIssuer, auth, + userInfo: mockUserInfo, }); await expect( diff --git a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts index 4f9b33d021..269c7131dc 100644 --- a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts +++ b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts @@ -32,6 +32,7 @@ import { TokenParams, } from '@backstage/plugin-auth-node'; import { CatalogIdentityClient } from '../catalog/CatalogIdentityClient'; +import { UserInfoDatabase } from '../../database/UserInfoDatabase'; function getDefaultOwnershipEntityRefs(entity: Entity) { const membershipRefs = @@ -51,6 +52,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext { tokenIssuer: TokenIssuer; auth: AuthService; ownershipResolver?: AuthOwnershipResolver; + userInfo: UserInfoDatabase; }): CatalogAuthResolverContext { const catalogIdentityClient = new CatalogIdentityClient({ catalog: options.catalog, @@ -63,6 +65,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext { catalogIdentityClient, options.catalog, options.auth, + options.userInfo, options.ownershipResolver, ); } @@ -73,11 +76,29 @@ export class CatalogAuthResolverContext implements AuthResolverContext { public readonly catalogIdentityClient: CatalogIdentityClient, private readonly catalog: CatalogService, private readonly auth: AuthService, + private readonly userInfo: UserInfoDatabase, private readonly ownershipResolver?: AuthOwnershipResolver, ) {} async issueToken(params: TokenParams) { - return await this.tokenIssuer.issueToken(params); + const { sub, ent = [sub], ...additionalClaims } = params.claims; + const claims = { + sub, + ent, + ...additionalClaims, + }; + + const issuedToken = await this.tokenIssuer.issueToken({ + claims, + }); + + // Store the user info in the database upon successful token + // issuance so that it can be retrieved later by limited user tokens + await this.userInfo.addUserInfo({ + claims, + }); + + return issuedToken; } async findCatalogUser(query: AuthResolverCatalogUserQuery) { @@ -160,7 +181,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext { entity, ); - return await this.tokenIssuer.issueToken({ + return await this.issueToken({ claims: { sub: stringifyEntityRef(entity), ent: ownershipEntityRefs, @@ -180,7 +201,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext { }), ); - return await this.tokenIssuer.issueToken({ + return await this.issueToken({ claims: { sub: userEntityRef, ent: [userEntityRef], diff --git a/plugins/auth-backend/src/migrations.test.ts b/plugins/auth-backend/src/migrations.test.ts index b4a6572a86..f9575c70fd 100644 --- a/plugins/auth-backend/src/migrations.test.ts +++ b/plugins/auth-backend/src/migrations.test.ts @@ -107,4 +107,83 @@ describe('migrations', () => { await knex.destroy(); }, ); + + it.each(databases.eachSupportedId())( + '20250707164600_user_created_at.js, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateUntilBefore(knex, '20250707164600_user_created_at.js'); + + if (knex.client.config.client.includes('sqlite')) { + // Sqlite doesn't support adding a column with non-constant default when table has data + // so we just test that the migration runs without errors + await migrateUpOnce(knex); + + return; + } + + const user_info = JSON.stringify({ + claims: { + ent: ['group:default/group1', 'group:default/group2'], + }, + }); + + await knex + .insert({ + user_entity_ref: 'user:default/backstage-user', + user_info, + exp: knex.fn.now(), + }) + .into('user_info'); + + const { exp } = await knex('user_info').first(); + + await migrateUpOnce(knex); + + const { created_at, updated_at } = await knex('user_info').first(); + + expect(updated_at).toEqual(exp); + expect(created_at).toBeDefined(); + + await knex + .insert({ + user_entity_ref: 'user:default/backstage-user', + user_info, + updated_at: knex.fn.now(), + }) + .into('user_info') + .onConflict(['user_entity_ref']) + .merge(); + + await knex + .insert({ + user_entity_ref: 'user:default/backstage-user-2', + user_info, + updated_at: knex.fn.now(), + }) + .into('user_info'); + + await expect( + knex('user_info').select('created_at', 'updated_at'), + ).resolves.toEqual([ + { + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + { + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ]); + + await migrateDownOnce(knex); + + await expect(knex('user_info').select('exp')).resolves.toEqual([ + { exp: expect.any(Date) }, + { exp: expect.any(Date) }, + ]); + + await knex.destroy(); + }, + ); }); diff --git a/plugins/auth-backend/src/providers/router.ts b/plugins/auth-backend/src/providers/router.ts index d04347e7b3..8505c1f2bd 100644 --- a/plugins/auth-backend/src/providers/router.ts +++ b/plugins/auth-backend/src/providers/router.ts @@ -27,6 +27,7 @@ import Router from 'express-promise-router'; import { Minimatch } from 'minimatch'; import { CatalogAuthResolverContext } from '../lib/resolvers/CatalogAuthResolverContext'; import { TokenIssuer } from '../identity/types'; +import { UserInfoDatabase } from '../database/UserInfoDatabase'; export type ProviderFactories = { [s: string]: AuthProviderFactory }; @@ -40,6 +41,7 @@ export function bindProviderRouters( logger: LoggerService; auth: AuthService; tokenIssuer: TokenIssuer; + userInfo: UserInfoDatabase; ownershipResolver?: AuthOwnershipResolver; catalog: CatalogService; }, @@ -54,6 +56,7 @@ export function bindProviderRouters( tokenIssuer, catalog, ownershipResolver, + userInfo, } = options; const providersConfig = config.getOptionalConfig('auth.providers'); @@ -82,6 +85,7 @@ export function bindProviderRouters( tokenIssuer, auth, ownershipResolver, + userInfo, }), }); diff --git a/plugins/auth-backend/src/service/OidcRouter.test.ts b/plugins/auth-backend/src/service/OidcRouter.test.ts new file mode 100644 index 0000000000..dbc6c88f93 --- /dev/null +++ b/plugins/auth-backend/src/service/OidcRouter.test.ts @@ -0,0 +1,151 @@ +/* + * 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 { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import Router from 'express-promise-router'; +import request from 'supertest'; +import { OidcRouter } from './OidcRouter'; +import { UserInfoDatabase } from '../database/UserInfoDatabase'; + +describe('OidcRouter', () => { + describe('/v1/userinfo', () => { + it('should return user info for full tokens', async () => { + const auth = mockServices.auth.mock(); + const mockUserInfo = { + getUserInfo: jest.fn().mockResolvedValue({ + claims: { + sub: 'k/ns:n', + ent: ['k/ns:a', 'k/ns:b'], + }, + }), + } as unknown as UserInfoDatabase; + + const { server } = await startTestBackend({ + features: [ + createBackendPlugin({ + pluginId: 'auth', + register(reg) { + reg.registerInit({ + deps: { httpRouter: coreServices.httpRouter }, + async init({ httpRouter }) { + const router = Router(); + + router.use( + OidcRouter.create({ + auth, + tokenIssuer: {} as any, + baseUrl: 'http://localhost:7000', + userInfo: mockUserInfo, + }).getRouter(), + ); + httpRouter.use(router); + httpRouter.addAuthPolicy({ + path: '/', + allow: 'unauthenticated', + }); + }, + }); + }, + }), + ], + }); + + auth.authenticate.mockResolvedValueOnce({} as any); + auth.isPrincipal.mockReturnValueOnce(true); + + await request(server) + .get('/api/auth/v1/userinfo') + .set( + 'Authorization', + `Bearer h.${btoa( + JSON.stringify({ sub: 'k/ns:n', ent: ['k/ns:a', 'k/ns:b'] }), + )}.s`, + ) + .expect(200, { + claims: { + sub: 'k/ns:n', + ent: ['k/ns:a', 'k/ns:b'], + }, + }); + + expect(mockUserInfo.getUserInfo).toHaveBeenCalledWith('k/ns:n'); + }); + + it('should return user info for limited tokens', async () => { + const auth = mockServices.auth.mock(); + const mockUserInfo = { + getUserInfo: jest.fn().mockResolvedValue({ + claims: { + sub: 'k/ns:n', + ent: ['k/ns:a', 'k/ns:b'], + }, + }), + } as unknown as UserInfoDatabase; + + const { server } = await startTestBackend({ + features: [ + createBackendPlugin({ + pluginId: 'auth', + register(reg) { + reg.registerInit({ + deps: { httpRouter: coreServices.httpRouter }, + async init({ httpRouter }) { + const router = Router(); + + router.use( + OidcRouter.create({ + auth, + tokenIssuer: {} as any, + baseUrl: 'http://localhost:7000', + userInfo: mockUserInfo, + }).getRouter(), + ); + httpRouter.use(router); + httpRouter.addAuthPolicy({ + path: '/', + allow: 'unauthenticated', + }); + }, + }); + }, + }), + ], + }); + + auth.authenticate.mockResolvedValueOnce({} as any); + auth.isPrincipal.mockReturnValueOnce(true); + + await request(server) + .get('/api/auth/v1/userinfo') + .set( + 'Authorization', + `Bearer h.${btoa(JSON.stringify({ sub: 'k/ns:n' }))}.s`, + ) + .expect(200, { + claims: { + sub: 'k/ns:n', + ent: ['k/ns:a', 'k/ns:b'], + }, + }); + + expect(mockUserInfo.getUserInfo).toHaveBeenCalledWith('k/ns:n'); + }); + }); +}); diff --git a/plugins/auth-backend/src/service/OidcRouter.ts b/plugins/auth-backend/src/service/OidcRouter.ts new file mode 100644 index 0000000000..6ada071c44 --- /dev/null +++ b/plugins/auth-backend/src/service/OidcRouter.ts @@ -0,0 +1,73 @@ +/* + * 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 Router from 'express-promise-router'; +import { OidcService } from './OidcService'; +import { AuthenticationError } from '@backstage/errors'; +import { AuthService } from '@backstage/backend-plugin-api'; +import { TokenIssuer } from '../identity/types'; +import { UserInfoDatabase } from '../database/UserInfoDatabase'; + +export class OidcRouter { + private constructor(private readonly oidc: OidcService) {} + + static create(options: { + auth: AuthService; + tokenIssuer: TokenIssuer; + baseUrl: string; + userInfo: UserInfoDatabase; + }) { + return new OidcRouter(OidcService.create(options)); + } + + public getRouter() { + const router = Router(); + + router.get('/.well-known/openid-configuration', (_req, res) => { + res.json(this.oidc.getConfiguration()); + }); + + router.get('/.well-known/jwks.json', async (_req, res) => { + const { keys } = await this.oidc.listPublicKeys(); + res.json({ keys }); + }); + + router.get('/v1/token', (_req, res) => { + res.status(501).send('Not Implemented'); + }); + + // This endpoint doesn't use the regular HttpAuthoidc, since the contract + // is specifically for the header to be communicated in the Authorization + // header, regardless of token type + router.get('/v1/userinfo', async (req, res) => { + const matches = req.headers.authorization?.match(/^Bearer[ ]+(\S+)$/i); + const token = matches?.[1]; + if (!token) { + throw new AuthenticationError('No token provided'); + } + + const userInfo = await this.oidc.getUserInfo({ token }); + + if (!userInfo) { + res.status(404).send('User info not found'); + return; + } + + res.json(userInfo); + }); + + return router; + } +} diff --git a/plugins/auth-backend/src/service/OidcService.ts b/plugins/auth-backend/src/service/OidcService.ts new file mode 100644 index 0000000000..5024b2cc8c --- /dev/null +++ b/plugins/auth-backend/src/service/OidcService.ts @@ -0,0 +1,92 @@ +/* + * 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 { AuthService } from '@backstage/backend-plugin-api'; +import { TokenIssuer } from '../identity/types'; +import { UserInfoDatabase } from '../database/UserInfoDatabase'; +import { InputError } from '@backstage/errors'; +import { decodeJwt } from 'jose'; + +export class OidcService { + private constructor( + private readonly auth: AuthService, + private readonly tokenIssuer: TokenIssuer, + private readonly baseUrl: string, + private readonly userInfo: UserInfoDatabase, + ) {} + + static create(options: { + auth: AuthService; + tokenIssuer: TokenIssuer; + baseUrl: string; + userInfo: UserInfoDatabase; + }) { + return new OidcService( + options.auth, + options.tokenIssuer, + options.baseUrl, + options.userInfo, + ); + } + + public getConfiguration() { + return { + issuer: this.baseUrl, + token_endpoint: `${this.baseUrl}/v1/token`, + userinfo_endpoint: `${this.baseUrl}/v1/userinfo`, + jwks_uri: `${this.baseUrl}/.well-known/jwks.json`, + response_types_supported: ['id_token'], + subject_types_supported: ['public'], + id_token_signing_alg_values_supported: [ + 'RS256', + 'RS384', + 'RS512', + 'ES256', + 'ES384', + 'ES512', + 'PS256', + 'PS384', + 'PS512', + 'EdDSA', + ], + scopes_supported: ['openid'], + token_endpoint_auth_methods_supported: [], + claims_supported: ['sub', 'ent'], + grant_types_supported: [], + }; + } + + public async listPublicKeys() { + return await this.tokenIssuer.listPublicKeys(); + } + + public async getUserInfo({ token }: { token: string }) { + const credentials = await this.auth.authenticate(token, { + allowLimitedAccess: true, + }); + if (!this.auth.isPrincipal(credentials, 'user')) { + throw new InputError( + 'Userinfo endpoint must be called with a token that represents a user principal', + ); + } + + const { sub: userEntityRef } = decodeJwt(token); + + if (typeof userEntityRef !== 'string') { + throw new Error('Invalid user token, user entity ref must be a string'); + } + return await this.userInfo.getUserInfo(userEntityRef); + } +} diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index fd9373d5a3..5012c90106 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -27,10 +27,9 @@ import { import { AuthOwnershipResolver } from '@backstage/plugin-auth-node'; import { CatalogService } from '@backstage/plugin-catalog-node'; import { NotFoundError } from '@backstage/errors'; -import { bindOidcRouter } from '../identity/router'; import { KeyStores } from '../identity/KeyStores'; import { TokenFactory } from '../identity/TokenFactory'; -import { UserInfoDatabaseHandler } from '../identity/UserInfoDatabaseHandler'; +import { UserInfoDatabase } from '../database/UserInfoDatabase'; import session from 'express-session'; import connectSessionKnex from 'connect-session-knex'; import passport from 'passport'; @@ -40,6 +39,7 @@ import { TokenIssuer } from '../identity/types'; import { StaticTokenIssuer } from '../identity/StaticTokenIssuer'; import { StaticKeyStore } from '../identity/StaticKeyStore'; import { bindProviderRouters, ProviderFactories } from '../providers/router'; +import { OidcRouter } from './OidcRouter'; interface RouterOptions { logger: LoggerService; @@ -60,7 +60,7 @@ export async function createRouter( logger, config, discovery, - database, + database: db, tokenFactoryAlgorithm, providerFactories = {}, } = options; @@ -70,16 +70,16 @@ export async function createRouter( const appUrl = config.getString('app.baseUrl'); const authUrl = await discovery.getExternalBaseUrl('auth'); const backstageTokenExpiration = readBackstageTokenExpiration(config); - const authDb = AuthDatabase.create(database); + const database = AuthDatabase.create(db); const keyStore = await KeyStores.fromConfig(config, { logger, - database: authDb, + database, }); - const userInfoDatabaseHandler = new UserInfoDatabaseHandler( - await authDb.get(), - ); + const userInfo = await UserInfoDatabase.create({ + database, + }); const omitClaimsFromToken = config.getOptionalBoolean( 'auth.omitIdentityTokenOwnershipClaim', @@ -94,7 +94,6 @@ export async function createRouter( logger: logger.child({ component: 'token-factory' }), issuer: authUrl, sessionExpirationSeconds: backstageTokenExpiration, - userInfoDatabaseHandler, omitClaimsFromToken, }, keyStore as StaticKeyStore, @@ -108,7 +107,6 @@ export async function createRouter( algorithm: tokenFactoryAlgorithm ?? config.getOptionalString('auth.identityTokenAlgorithm'), - userInfoDatabaseHandler, omitClaimsFromToken, }); } @@ -126,7 +124,7 @@ export async function createRouter( cookie: { secure: enforceCookieSSL ? 'auto' : false }, store: new KnexSessionStore({ createtable: false, - knex: await authDb.get(), + knex: await database.get(), }), }), ); @@ -146,15 +144,18 @@ export async function createRouter( tokenIssuer, ...options, auth: options.auth, + userInfo, }); - bindOidcRouter(router, { + const oidcRouter = OidcRouter.create({ auth: options.auth, tokenIssuer, baseUrl: authUrl, - userInfoDatabaseHandler, + userInfo, }); + router.use(oidcRouter.getRouter()); + // Gives a more helpful error message than a plain 404 router.use('/:provider/', req => { const { provider } = req.params; diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index cd4b5b58bf..178d799921 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-auth-node +## 0.6.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + +## 0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 0.6.4 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index b5ec590eb3..5d20e7aced 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.4", + "version": "0.6.5", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index da56041530..1152bd0666 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-auth-react +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + ## 0.1.16 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 50296070ea..c7a376d18a 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.16", + "version": "0.1.17", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 6924ab6310..637250335d 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1 + +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 97150d6e8d..60b0b10970 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.0", + "version": "0.3.1", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index bdaf217a08..1e276825de 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-defaults@0.11.1 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/integration@1.17.1-next.1 + - @backstage/integration-aws-node@0.1.17-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.4.12 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index f5b56f705a..4041cbedc6 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.12", + "version": "0.4.13", "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 c68daded70..5a31dc1046 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.8-next.0 + +### Patch Changes + +- b3aa80e: `host` should be optional in `config` schema + +## 0.3.7 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.3.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/config.d.ts b/plugins/catalog-backend-module-azure/config.d.ts index f6c3bab068..50af529907 100644 --- a/plugins/catalog-backend-module-azure/config.d.ts +++ b/plugins/catalog-backend-module-azure/config.d.ts @@ -28,9 +28,9 @@ export interface Config { azureDevOps?: { [name: string]: { /** - * (Optional) The DevOps host; leave empty for `dev.azure.com`, otherwise set to your self-hosted instance host. + * (Optional) The DevOps host; defaults to `dev.azure.com` if left empty, otherwise set to your self-hosted instance host. */ - host: string; + host?: string; /** * (Required) Your organization slug. */ diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 6892b859fe..94d5a6fd39 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.6", + "version": "0.3.8-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 283b8d22ec..aa57d557a4 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-openapi-utils@0.5.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/backend-openapi-utils@0.5.5-next.0 + ## 0.5.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index b81797fbf9..691010f691 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.3", + "version": "0.5.4", "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 66e8f9a5c2..0b9bc4b94a 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.5.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-bitbucket-cloud-common@0.3.1-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.5.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 2fdc1ba5c7..05f1c1312c 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.0", + "version": "0.5.1", "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 5bc457524c..6f68d1022b 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.5.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.5.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 67f25e1ada..5863eb49cb 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.0", + "version": "0.5.1", "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 1831056e4e..de990d503e 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.10 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 71d9a82e01..61091aac4d 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.9", + "version": "0.3.10", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index f82bccfecb..92db515723 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.3.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index aada0b8773..2a3584d704 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.3", + "version": "0.3.4", "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 bea863224c..147fe26f73 100644 --- a/plugins/catalog-backend-module-gitea/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-gitea +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.1.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitea/package.json b/plugins/catalog-backend-module-gitea/package.json index 13b806f0d9..ee27539036 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.1", + "version": "0.1.2", "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 1892a829e4..20212a9a5c 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-backend-module-github@0.10.1 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-backend-module-github@0.10.1-next.1 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.10.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/config@1.3.2 + ## 0.3.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 8bf5977b2e..90c9b0b472 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.11", + "version": "0.3.12", "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 c67c3a3ded..022b432fa2 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-catalog-backend-module-github +## 0.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0 + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.10.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-backend@3.0.0-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.10.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.10.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 5a445be46c..0e6fbe33af 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.10.0", + "version": "0.10.1", "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 fa25b06614..e6dbfbd7a2 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.1 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.1-next.1 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.7.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.2.10 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 1d455b84a5..7d65b4f858 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.10", + "version": "0.2.11", "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 5725caf17a..91681fc233 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-defaults@0.11.1 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.7.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 3cc3862610..638f033151 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.0", + "version": "0.7.1", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index d7ce338d6d..d75d0e224e 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -72,7 +72,7 @@ function setupFakeServer( assertion(req); } - if (req.headers.get('private-token') !== 'test-token') { + if (req.headers.get('authorization') !== 'Bearer test-token') { return res(ctx.status(401), ctx.json({})); } const page = req.url.searchParams.get('page'); @@ -104,8 +104,11 @@ function setupFakeServer( rest.head( `${API_URL}/projects/:project_path/repository/files/:file_path`, (req, res, ctx) => { - if (req.headers.get('private-token') !== 'test-token') { - return res(ctx.status(401), ctx.json({})); + if (req.headers.get('authorization') !== 'Bearer test-token') { + return res( + ctx.status(401), + ctx.json({ message: '401 Unauthorized' }), + ); } const ref = req.url.searchParams.get('ref'); diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index a31aadc3b8..cf8fad8206 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.7.2 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- e2dd095: Fixed bug in `IncrementalIngestionEngine` by adding `burstLength` check when a burst completes +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0 + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-defaults@0.11.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 0.7.2-next.1 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- e2dd095: Fixed bug in `IncrementalIngestionEngine` by adding `burstLength` check when a burst completes +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-backend@3.0.0-next.1 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0-next.0 + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + ## 0.7.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index fd29be61ea..1b56ff5db0 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.1", + "version": "0.7.2", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/report.api.md b/plugins/catalog-backend-module-incremental-ingestion/report.api.md index b1fac447b2..fa69a0987c 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/report.api.md +++ b/plugins/catalog-backend-module-incremental-ingestion/report.api.md @@ -8,8 +8,6 @@ import type { DeferredEntity } from '@backstage/plugin-catalog-node'; import { EventParams } from '@backstage/plugin-events-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { HumanDuration } from '@backstage/types'; -import { IncrementalEntityProvider as IncrementalEntityProvider_2 } from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; -import { IncrementalEntityProviderOptions as IncrementalEntityProviderOptions_2 } from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; // @public const catalogModuleIncrementalIngestionEntityProvider: BackendFeature; @@ -68,8 +66,8 @@ export interface IncrementalEntityProviderOptions { // @public export interface IncrementalIngestionProviderExtensionPoint { addProvider(config: { - options: IncrementalEntityProviderOptions_2; - provider: IncrementalEntityProvider_2; + options: IncrementalEntityProviderOptions; + provider: IncrementalEntityProvider; }): void; } diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.test.ts new file mode 100644 index 0000000000..4bfe0666da --- /dev/null +++ b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.test.ts @@ -0,0 +1,211 @@ +/* + * 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 { IncrementalIngestionEngine } from './IncrementalIngestionEngine'; +import { IterationEngineOptions } from '../types'; +import { performance } from 'perf_hooks'; + +jest.setTimeout(60_000); + +describe('IncrementalIngestionEngine - Burst Length', () => { + const createMockProvider = () => ({ + getProviderName: jest.fn().mockReturnValue('test-provider'), + next: jest.fn(), + around: jest.fn(), + }); + + const createMockManager = () => + ({ + getLastMark: jest.fn().mockResolvedValue(null), + createMark: jest.fn().mockResolvedValue(undefined), + createMarkEntities: jest.fn().mockResolvedValue(undefined), + computeRemoved: jest.fn().mockResolvedValue({ total: 0, removed: [] }), + } as any); + + const createMockConnection = () => + ({ + applyMutation: jest.fn().mockResolvedValue(undefined), + refresh: jest.fn().mockResolvedValue(undefined), + } as any); + + const createMockLogger = () => + ({ + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + child: jest.fn().mockReturnThis(), + } as any); + + it('should respect burst length and stop burst when time limit exceeded', async () => { + const mockProvider = createMockProvider(); + const mockManager = createMockManager(); + const mockConnection = createMockConnection(); + const mockLogger = createMockLogger(); + + const options: IterationEngineOptions = { + provider: mockProvider, + manager: mockManager, + connection: mockConnection, + burstLength: { milliseconds: 100 }, // Short burst length for testing + restLength: { minutes: 1 }, + logger: mockLogger, + ready: Promise.resolve(), + }; + + const engine = new IncrementalIngestionEngine(options); + + let callCount = 0; + mockProvider.around.mockImplementation(async fn => { + await fn({}); + }); + + // Mock provider.next to return multiple batches that never complete + // Each call takes some time to simulate real processing + mockProvider.next.mockImplementation(async () => { + callCount++; + // Add a small delay to ensure we exceed burst length + await new Promise(resolve => setTimeout(resolve, 30)); + return { + done: false, + entities: [ + { + entity: { + kind: 'Component', + metadata: { name: `test-component-${callCount}` }, + }, + }, + ], + cursor: `cursor-${callCount}`, + }; + }); + + const signal = new AbortController().signal; + const start = performance.now(); + + const result = await engine.ingestOneBurst('test-ingestion', signal); + + const duration = performance.now() - start; + + // Verify that the burst was stopped due to time limit, not completion + expect(result).toBe(false); + expect(duration).toBeGreaterThanOrEqual(100); + expect(duration).toBeLessThan(200); + expect(mockProvider.next).toHaveBeenCalledTimes(callCount); + + expect(callCount).toBeGreaterThan(1); + }); + + it('should complete burst normally when provider returns done before burst length', async () => { + const mockProvider = createMockProvider(); + const mockManager = createMockManager(); + const mockConnection = createMockConnection(); + const mockLogger = createMockLogger(); + + const options: IterationEngineOptions = { + provider: mockProvider, + manager: mockManager, + connection: mockConnection, + burstLength: { seconds: 10 }, + restLength: { minutes: 1 }, + logger: mockLogger, + ready: Promise.resolve(), + }; + + const engine = new IncrementalIngestionEngine(options); + + mockProvider.around.mockImplementation(async fn => { + await fn({}); + }); + + // Mock provider.next to return done after first call + mockProvider.next.mockResolvedValueOnce({ + done: true, + entities: [ + { + entity: { + kind: 'Component', + metadata: { name: 'test-component-1' }, + }, + }, + ], + cursor: 'final-cursor', + }); + + const signal = new AbortController().signal; + const start = performance.now(); + const result = await engine.ingestOneBurst('test-ingestion', signal); + const duration = performance.now() - start; + + expect(result).toBe(true); + expect(mockProvider.next).toHaveBeenCalledTimes(1); + expect(duration).toBeLessThan(100); // Should complete quickly since provider returns done immediately + }); + + it('should stop burst when time limit is reached', async () => { + const mockProvider = createMockProvider(); + const mockManager = createMockManager(); + const mockConnection = createMockConnection(); + const mockLogger = createMockLogger(); + + const options: IterationEngineOptions = { + provider: mockProvider, + manager: mockManager, + connection: mockConnection, + burstLength: { milliseconds: 80 }, + restLength: { minutes: 1 }, + logger: mockLogger, + ready: Promise.resolve(), + }; + + const engine = new IncrementalIngestionEngine(options); + + let callCount = 0; + mockProvider.around.mockImplementation(async fn => { + await fn({}); + }); + + mockProvider.next.mockImplementation(async () => { + callCount++; + await new Promise(resolve => setTimeout(resolve, 30)); + return { + done: false, + entities: [ + { + entity: { + kind: 'Component', + metadata: { name: `test-component-${callCount}` }, + }, + }, + ], + cursor: `cursor-${callCount}`, + }; + }); + + const signal = new AbortController().signal; + const start = performance.now(); + + const result = await engine.ingestOneBurst('test-ingestion', signal); + + const duration = performance.now() - start; + + expect(result).toBe(false); + expect(mockProvider.next).toHaveBeenCalledTimes(3); + expect(callCount).toBe(3); + expect(duration).toBeGreaterThanOrEqual(90); + expect(duration).toBeLessThan(120); + }); +}); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts index e005d29292..95510e78e4 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts @@ -27,6 +27,7 @@ import { HumanDuration } from '@backstage/types'; export class IncrementalIngestionEngine implements IterationEngine { private readonly restLength: Duration; + private readonly burstLength: Duration; private readonly backoff: HumanDuration[]; private readonly lastStarted: Gauge; private readonly lastCompleted: Gauge; @@ -38,6 +39,7 @@ export class IncrementalIngestionEngine implements IterationEngine { this.manager = options.manager; this.restLength = Duration.fromObject(options.restLength); + this.burstLength = Duration.fromObject(options.burstLength); this.backoff = options.backoff ?? [ { minutes: 1 }, { minutes: 5 }, @@ -247,6 +249,14 @@ export class IncrementalIngestionEngine implements IterationEngine { }); if (signal.aborted || next.done) { break; + } else if ( + performance.now() - start > + this.burstLength.as('milliseconds') + ) { + this.options.logger.info( + `incremental-engine: Ingestion '${id}' burst ending after ${this.burstLength.toHuman()}.`, + ); + break; } else { next = await this.options.provider.next(context, next.cursor); count++; diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts index 9e931c11fd..8c18f09798 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts @@ -20,12 +20,12 @@ import { createExtensionPoint, } from '@backstage/backend-plugin-api'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; +import { WrapperProviders } from './WrapperProviders'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; import { IncrementalEntityProvider, IncrementalEntityProviderOptions, -} from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; -import { WrapperProviders } from './WrapperProviders'; -import { eventsServiceRef } from '@backstage/plugin-events-node'; +} from '../types'; /** * @public diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/types.ts b/plugins/catalog-backend-module-incremental-ingestion/src/types.ts index 75aecf8fa5..04a73bd364 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/types.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/types.ts @@ -188,6 +188,7 @@ export interface IterationEngineOptions { manager: IncrementalIngestionDatabaseManager; provider: IncrementalEntityProvider; restLength: HumanDuration; + burstLength: HumanDuration; ready: Promise; backoff?: IncrementalEntityProviderOptions['backoff']; rejectRemovalsAbovePercentage?: number; diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 1486c92d05..3a35183226 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.11.7 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.11.7-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + ## 0.11.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index cae1834b8d..0d78cded65 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.11.6", + "version": "0.11.7", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/report.api.md b/plugins/catalog-backend-module-ldap/report.api.md index c5eddd8778..1bcf59affb 100644 --- a/plugins/catalog-backend-module-ldap/report.api.md +++ b/plugins/catalog-backend-module-ldap/report.api.md @@ -12,7 +12,6 @@ import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { GroupEntity } from '@backstage/catalog-model'; -import { GroupTransformer as GroupTransformer_2 } from '@backstage/plugin-catalog-backend-module-ldap'; import { JsonValue } from '@backstage/types'; import { LocationSpec } from '@backstage/plugin-catalog-common'; import { LoggerService } from '@backstage/backend-plugin-api'; @@ -22,7 +21,6 @@ import { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugi import { SearchEntry } from 'ldapjs'; import { SearchOptions } from 'ldapjs'; import { UserEntity } from '@backstage/catalog-model'; -import { UserTransformer as UserTransformer_2 } from '@backstage/plugin-catalog-backend-module-ldap'; // @public export type BindConfig = { @@ -152,10 +150,10 @@ export type LdapOrgEntityProviderOptions = // @public export interface LdapOrgEntityProviderTransformsExtensionPoint { setGroupTransformer( - transformer: GroupTransformer_2 | Record, + transformer: GroupTransformer | Record, ): void; setUserTransformer( - transformer: UserTransformer_2 | Record, + transformer: UserTransformer | Record, ): void; } diff --git a/plugins/catalog-backend-module-ldap/src/module.ts b/plugins/catalog-backend-module-ldap/src/module.ts index ad76b133f1..dd47bf48da 100644 --- a/plugins/catalog-backend-module-ldap/src/module.ts +++ b/plugins/catalog-backend-module-ldap/src/module.ts @@ -20,11 +20,8 @@ import { createExtensionPoint, } from '@backstage/backend-plugin-api'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { - GroupTransformer, - UserTransformer, -} from '@backstage/plugin-catalog-backend-module-ldap'; import { LdapOrgEntityProvider } from './processors'; +import { GroupTransformer, UserTransformer } from './ldap/types'; /** * Interface for {@link LdapOrgEntityProviderTransformsExtensionPoint}. diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 16aa0436e0..85d3d62129 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-backend@3.0.0-next.1 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.0-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + ## 0.1.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index fa0b89de25..5f072e98bc 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.11", + "version": "0.1.12", "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 b844e52e5b..79a4bd5f85 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.7.2 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.7.2-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + ## 0.7.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 34b472b500..09cba39edc 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.7.1", + "version": "0.7.2", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/report.api.md b/plugins/catalog-backend-module-msgraph/report.api.md index 02d3949d04..c6687a638a 100644 --- a/plugins/catalog-backend-module-msgraph/report.api.md +++ b/plugins/catalog-backend-module-msgraph/report.api.md @@ -11,18 +11,14 @@ import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { GroupEntity } from '@backstage/catalog-model'; -import { GroupTransformer as GroupTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; import { LocationSpec } from '@backstage/plugin-catalog-common'; import { LoggerService } from '@backstage/backend-plugin-api'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; -import { OrganizationTransformer as OrganizationTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; -import { ProviderConfigTransformer as ProviderConfigTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api'; import { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; import { TokenCredential } from '@azure/identity'; import { UserEntity } from '@backstage/catalog-model'; -import { UserTransformer as UserTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; // @public const catalogModuleMicrosoftGraphOrgEntityProvider: BackendFeature; @@ -184,20 +180,20 @@ export const microsoftGraphOrgEntityProviderTransformExtensionPoint: ExtensionPo // @public export interface MicrosoftGraphOrgEntityProviderTransformsExtensionPoint { setGroupTransformer( - transformer: GroupTransformer_2 | Record, + transformer: GroupTransformer | Record, ): void; setOrganizationTransformer( transformer: - | OrganizationTransformer_2 - | Record, + | OrganizationTransformer + | Record, ): void; setProviderConfigTransformer( transformer: - | ProviderConfigTransformer_2 - | Record, + | ProviderConfigTransformer + | Record, ): void; setUserTransformer( - transformer: UserTransformer_2 | Record, + transformer: UserTransformer | Record, ): void; } diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts index 262c56cf3f..a11748f021 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts @@ -25,7 +25,7 @@ import { OrganizationTransformer, ProviderConfigTransformer, UserTransformer, -} from '@backstage/plugin-catalog-backend-module-msgraph'; +} from '../microsoftGraph/types'; import { MicrosoftGraphOrgEntityProvider } from '../processors'; /** diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 5fe46b66d9..594e817668 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/catalog-model@1.7.4 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.2.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 34acb98afb..dbb8c83461 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.11", + "version": "0.2.12", "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 db9f89b5d3..8579359e3c 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.12 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.2.12-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + ## 0.2.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 04f83433e9..5022efb68a 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.11", + "version": "0.2.12", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts b/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts index 891b19691a..9527ddd774 100644 --- a/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts +++ b/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { PuppetDbEntityProviderConfig } from '../providers'; +import { PuppetDbEntityProviderConfig } from '../providers/PuppetDbEntityProviderConfig'; import { PuppetNode, ResourceTransformer } from './types'; import { ResourceEntity } from '@backstage/catalog-model'; import { defaultResourceTransformer } from './transformers'; diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index ac96e7a98c..11373c04f5 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + ## 0.2.9 ### 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 3e01eb7b24..c97273b97c 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.9", + "version": "0.2.10", "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 519f0542d0..65a6b0c955 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.6.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.9 + +## 0.6.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.9-next.0 + ## 0.6.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 0c14e41a28..e7a62c41de 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.1", + "version": "0.6.2", "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 5bdf7ce965..6f0bde0bd9 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-catalog-backend +## 3.0.0 + +### Major Changes + +- 5127ebe: **BREAKING**: The default `catalog.stitchingStrategy` has been switched to `{ mode: 'deferred' }`. +- d675d96: **BREAKING**: The relations compatibility mode is no longer enabled by default, and the `disableRelationsCompatiblity` flag has been removed. To re-enable relations compatibility, the new `enableRelationsCompatibility` flag can be used instead. +- 2339363: **BREAKING:** The experimental `catalog.useUrlReadersSearch` configuration flag (introduced in v1.36) has been removed. + + The `UrlReaderProcessor` now always uses the `search` method of `UrlReaders`. Built-in `UrlReaderService` implementations have been updated accordingly. + If you use custom `UrlReaderService` implementations, you need to adapt their `search` method to correctly handle both specific URLs and potential + search patterns (see changes on built-in readers [in the original PR](https://github.com/backstage/backstage/pull/28379/files#diff-68b0452f173ee54bdd40f7b5e047a9cb8bb59200425622c212c217b76dac1d1b)). + + Previous behavior was to call the `search` method only if the parsed Git URL's filename contained a wildcard and use `readUrl` otherwise. Each `UrlReaderService` must implement this logic in the `search` method instead. + + This allows each `UrlReaderService` implementation to check whether it's a search URL (that contains a wildcard pattern) or not using logic that is specific to each provider. + +- 687bfc8: **BREAKING**: The default `catalog.orphanStrategy` has been switched to `'delete'`. +- 5de7a9d: **BREAKING**: The default `catalog.orphanProviderStrategy` has been switched to `'delete'`. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/integration@1.17.1 + - @backstage/backend-openapi-utils@0.5.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + +## 3.0.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/backend-openapi-utils@0.5.5-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 3.0.0-next.0 + +### Major Changes + +- 2339363: **BREAKING:** The experimental `catalog.useUrlReadersSearch` configuration flag (introduced in v1.36) has been removed. + + The `UrlReaderProcessor` now always uses the `search` method of `UrlReaders`. Built-in `UrlReaderService` implementations have been updated accordingly. + If you use custom `UrlReaderService` implementations, you need to adapt their `search` method to correctly handle both specific URLs and potential + search patterns (see changes on built-in readers [in the original PR](https://github.com/backstage/backstage/pull/28379/files#diff-68b0452f173ee54bdd40f7b5e047a9cb8bb59200425622c212c217b76dac1d1b)). + + Previous behavior was to call the `search` method only if the parsed Git URL's filename contained a wildcard and use `readUrl` otherwise. Each `UrlReaderService` must implement this logic in the `search` method instead. + + This allows each `UrlReaderService` implementation to check whether it's a search URL (that contains a wildcard pattern) or not using logic that is specific to each provider. + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + ## 2.1.0 ### Minor Changes diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts index 3ba6047ada..6329bcb111 100644 --- a/plugins/catalog-backend/config.d.ts +++ b/plugins/catalog-backend/config.d.ts @@ -139,14 +139,14 @@ export interface Config { }>; /** - * Disables the compatibility layer for relations in returned entities that + * Enables the compatibility layer for relations in returned entities that * ensures that all relations objects have both `target` and `targetRef`. * - * Enabling this option significantly reduces the memory usage of the - * catalog, and slightly increases performance, but may break consumers that + * Enabling this option significantly increases the memory usage of the + * catalog, and slightly reduces performance, but may avoid breaking consumers that * rely on the existence of `target` in the relations objects. */ - disableRelationsCompatibility?: boolean; + enableRelationsCompatibility?: boolean; /** * Disables the default backstage processors. @@ -160,19 +160,19 @@ export interface Config { /** * The strategy to use for entities that are orphaned, i.e. no longer have * any other entities or providers referencing them. The default value is - * "keep". + * "delete". */ orphanStrategy?: 'keep' | 'delete'; /** * The strategy to use for entities that are referenced by providers that are orphaned, * i.e. entities with no providers currently configured in the catalog. The default value is - * "keep". + * "delete". */ orphanProviderStrategy?: 'keep' | 'delete'; /** - * The strategy to use when stitching together the final entities. + * The strategy to use when stitching together the final entities. The default mode is "deferred". */ stitchingStrategy?: | { diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 627561b56e..f32fd2a7d9 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "2.1.0", + "version": "3.0.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts index a3ef926b47..56b95d901d 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts @@ -344,7 +344,7 @@ export class DefaultCatalogProcessingEngine { private startOrphanCleanup(): () => void { const orphanStrategy = - this.config.getOptionalString('catalog.orphanStrategy') ?? 'keep'; + this.config.getOptionalString('catalog.orphanStrategy') ?? 'delete'; if (orphanStrategy !== 'delete') { return () => {}; } diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index e50aa84d80..93a6a96eb0 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -463,8 +463,8 @@ export class CatalogBuilder { httpAuth, } = this.env; - const disableRelationsCompatibility = config.getOptionalBoolean( - 'catalog.disableRelationsCompatibility', + const enableRelationsCompatibility = Boolean( + config.getOptionalBoolean('catalog.enableRelationsCompatibility'), ); const policy = this.buildEntityPolicy(); @@ -503,7 +503,7 @@ export class CatalogBuilder { database: dbClient, logger, stitcher, - disableRelationsCompatibility, + enableRelationsCompatibility, }); let permissionsService: PermissionsService; @@ -619,12 +619,10 @@ export class CatalogBuilder { httpAuth, permissionsService, auditor, - disableRelationsCompatibility, + enableRelationsCompatibility, }); - if ( - config.getOptionalString('catalog.orphanProviderStrategy') === 'delete' - ) { + if (config.getOptionalString('catalog.orphanProviderStrategy') !== 'keep') { await evictEntitiesFromOrphanedProviders({ db: providerDatabase, providers: entityProviders, diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.test.ts b/plugins/catalog-backend/src/service/CatalogPlugin.test.ts index 9cec22322e..657cca16f3 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.test.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.test.ts @@ -67,5 +67,9 @@ describe('catalogPlugin', () => { paramsSchema: expect.any(Object), description: 'Test permission rule', }); + + // For some reason the test running breaks if this test exits too soon. + // This is an ugly workaround for now since it is blocking the 1.41 release. + await new Promise(resolve => setTimeout(resolve, 1000)); }); }); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index aad09d7de1..0b8dec71bb 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -525,7 +525,7 @@ describe('DefaultEntitiesCatalog', () => { ); it.each(databases.eachSupportedId())( - 'should return both target and targetRef for entities', + 'should return both target and targetRef for entities in compat mode', async databaseId => { await createDatabase(databaseId); await addEntity( @@ -557,6 +557,7 @@ describe('DefaultEntitiesCatalog', () => { database: knex, logger: mockServices.logger.mock(), stitcher, + enableRelationsCompatibility: true, }); const res = await catalog.entities(); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index a7b8fdc6c9..33847ea87b 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -105,19 +105,19 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { private readonly database: Knex; private readonly logger: LoggerService; private readonly stitcher: Stitcher; - private readonly disableRelationsCompatibility: boolean; + private readonly enableRelationsCompatibility: boolean; constructor(options: { database: Knex; logger: LoggerService; stitcher: Stitcher; - disableRelationsCompatibility?: boolean; + enableRelationsCompatibility?: boolean; }) { this.database = options.database; this.logger = options.logger; this.stitcher = options.stitcher; - this.disableRelationsCompatibility = Boolean( - options.disableRelationsCompatibility, + this.enableRelationsCompatibility = Boolean( + options.enableRelationsCompatibility, ); } @@ -199,15 +199,15 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { return { entities: processRawEntitiesResult( rows.map(r => r.final_entity!), - this.disableRelationsCompatibility - ? request?.fields - : e => { + this.enableRelationsCompatibility + ? e => { expandLegacyCompoundRelationsInEntity(e); if (request?.fields) { return request.fields(e); } return e; - }, + } + : request?.fields, ), pageInfo, }; diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index 193d5b5b52..0246a3d56b 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -136,38 +136,6 @@ describe('createRouter readonly disabled', () => { { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, ]; - entitiesCatalog.entities.mockResolvedValueOnce({ - entities: { type: 'object', entities: [entities[0]] }, - pageInfo: { hasNextPage: false }, - }); - - const response = await request(app).get('/entities'); - - expect(response.status).toEqual(200); - expect(response.body).toEqual(entities); - }); - - it('happy path: lists entities when by-entities emulation is enabled', async () => { - const router = await createRouter({ - entitiesCatalog, - locationService, - orchestrator, - logger: mockServices.logger.mock(), - refreshService, - config: new ConfigReader(undefined), - permissionIntegrationRouter: express.Router(), - auth: mockServices.auth(), - httpAuth: mockServices.httpAuth(), - locationAnalyzer, - permissionsService, - disableRelationsCompatibility: true, // added - }); - app = await wrapServer(express().use(router)); - - const entities: Entity[] = [ - { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, - ]; - entitiesCatalog.queryEntities.mockResolvedValueOnce({ items: { type: 'object', entities: [entities[0]] }, pageInfo: {}, @@ -180,34 +148,7 @@ describe('createRouter readonly disabled', () => { expect(response.body).toEqual(entities); }); - it('parses single and multiple request parameters and passes them down', async () => { - entitiesCatalog.entities.mockResolvedValueOnce({ - entities: { type: 'object', entities: [] }, - pageInfo: { hasNextPage: false }, - }); - const response = await request(app).get( - '/entities?filter=a=1,a=2,b=3&filter=c=4', - ); - - expect(response.status).toEqual(200); - expect(entitiesCatalog.entities).toHaveBeenCalledTimes(1); - expect(entitiesCatalog.entities).toHaveBeenCalledWith({ - filter: { - anyOf: [ - { - allOf: [ - { key: 'a', values: ['1', '2'] }, - { key: 'b', values: ['3'] }, - ], - }, - { key: 'c', values: ['4'] }, - ], - }, - credentials: mockCredentials.user(), - }); - }); - - it('parses single and multiple request parameters and passes them down when by-entities emulation is enabled', async () => { + it('happy path: lists entities with relations compat', async () => { const router = await createRouter({ entitiesCatalog, locationService, @@ -220,10 +161,26 @@ describe('createRouter readonly disabled', () => { httpAuth: mockServices.httpAuth(), locationAnalyzer, permissionsService, - disableRelationsCompatibility: true, // added + enableRelationsCompatibility: true, // added }); - app = await wrapServer(express().use(router)); + app = await wrapServer(express().use(router)); + const entities: Entity[] = [ + { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, + ]; + + entitiesCatalog.entities.mockResolvedValueOnce({ + entities: { type: 'object', entities: [entities[0]] }, + pageInfo: { hasNextPage: false }, + }); + + const response = await request(app).get('/entities'); + + expect(response.status).toEqual(200); + expect(response.body).toEqual(entities); + }); + + it('parses single and multiple request parameters and passes them down', async () => { entitiesCatalog.queryEntities.mockResolvedValueOnce({ items: { type: 'object', entities: [] }, pageInfo: {}, @@ -252,6 +209,48 @@ describe('createRouter readonly disabled', () => { skipTotalItems: true, }); }); + + it('parses single and multiple request parameters and passes them down with relations compat', async () => { + const router = await createRouter({ + entitiesCatalog, + locationService, + orchestrator, + logger: mockServices.logger.mock(), + refreshService, + config: new ConfigReader(undefined), + permissionIntegrationRouter: express.Router(), + auth: mockServices.auth(), + httpAuth: mockServices.httpAuth(), + locationAnalyzer, + permissionsService, + enableRelationsCompatibility: true, + }); + app = await wrapServer(express().use(router)); + entitiesCatalog.entities.mockResolvedValueOnce({ + entities: { type: 'object', entities: [] }, + pageInfo: { hasNextPage: false }, + }); + const response = await request(app).get( + '/entities?filter=a=1,a=2,b=3&filter=c=4', + ); + + expect(response.status).toEqual(200); + expect(entitiesCatalog.entities).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.entities).toHaveBeenCalledWith({ + filter: { + anyOf: [ + { + allOf: [ + { key: 'a', values: ['1', '2'] }, + { key: 'b', values: ['3'] }, + ], + }, + { key: 'c', values: ['4'] }, + ], + }, + credentials: mockCredentials.user(), + }); + }); }); describe('GET /entities/by-query', () => { @@ -941,7 +940,6 @@ describe('createRouter readonly and raw json enabled', () => { getLocationByEntity: jest.fn(), }; const router = await createRouter({ - disableRelationsCompatibility: true, entitiesCatalog, locationService, logger: mockServices.logger.mock(), diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index f4ce26b66b..2c9e63e8c4 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -81,7 +81,7 @@ export interface RouterOptions { permissionsService: PermissionsService; // TODO: Require AuditorService once `backend-legacy` is removed auditor?: AuditorService; - disableRelationsCompatibility?: boolean; + enableRelationsCompatibility?: boolean; } /** @@ -110,7 +110,7 @@ export async function createRouter( auth, httpAuth, auditor, - disableRelationsCompatibility = false, + enableRelationsCompatibility = false, } = options; const readonlyEnabled = @@ -179,7 +179,7 @@ export async function createRouter( // When pagination parameters are passed in, use the legacy slow path // that loads all entities into memory - if (pagination || disableRelationsCompatibility !== true) { + if (pagination || enableRelationsCompatibility === true) { const { entities, pageInfo } = await entitiesCatalog.entities({ filter, fields, @@ -204,7 +204,7 @@ export async function createRouter( await writeEntitiesResponse({ res, items: entities, - alwaysUseObjectMode: !disableRelationsCompatibility, + alwaysUseObjectMode: enableRelationsCompatibility, }); return; } @@ -295,7 +295,7 @@ export async function createRouter( await writeEntitiesResponse({ res, items, - alwaysUseObjectMode: !disableRelationsCompatibility, + alwaysUseObjectMode: enableRelationsCompatibility, responseWrapper: entities => ({ items: entities, ...meta, @@ -482,7 +482,7 @@ export async function createRouter( await writeEntitiesResponse({ res, items, - alwaysUseObjectMode: !disableRelationsCompatibility, + alwaysUseObjectMode: enableRelationsCompatibility, responseWrapper: entities => ({ items: entities, }), diff --git a/plugins/catalog-backend/src/stitching/types.ts b/plugins/catalog-backend/src/stitching/types.ts index bbb6223968..7c8a5c7d65 100644 --- a/plugins/catalog-backend/src/stitching/types.ts +++ b/plugins/catalog-backend/src/stitching/types.ts @@ -61,11 +61,11 @@ export function stitchingStrategyFromConfig(config: Config): StitchingStrategy { 'catalog.stitchingStrategy.mode', ); - if (strategyMode === undefined || strategyMode === 'immediate') { + if (strategyMode === 'immediate') { return { mode: 'immediate', }; - } else if (strategyMode === 'deferred') { + } else if (strategyMode === undefined || strategyMode === 'deferred') { const pollingIntervalKey = 'catalog.stitchingStrategy.pollingInterval'; const stitchTimeoutKey = 'catalog.stitchingStrategy.stitchTimeout'; diff --git a/plugins/catalog-backend/src/tests/integration.test.ts b/plugins/catalog-backend/src/tests/integration.test.ts index 400bbc7538..719c5e6ccf 100644 --- a/plugins/catalog-backend/src/tests/integration.test.ts +++ b/plugins/catalog-backend/src/tests/integration.test.ts @@ -205,7 +205,7 @@ class TestHarness { readonly #db: Knex; static async create(options: { - disableRelationsCompatibility?: boolean; + enableRelationsCompatibility?: boolean; logger?: LoggerService; db: Knex; permissions?: PermissionEvaluator; @@ -283,7 +283,7 @@ class TestHarness { database: options.db, logger, stitcher, - disableRelationsCompatibility: options?.disableRelationsCompatibility, + enableRelationsCompatibility: options?.enableRelationsCompatibility, }); const proxyProgressTracker = new ProxyProgressTracker( new NoopProgressTracker(), @@ -863,7 +863,6 @@ describe('Catalog Backend Integration', () => { it('should return valid responses in raw JSON mode', async () => { const harness = await TestHarness.create({ db: await databases.init('SQLITE_3'), - disableRelationsCompatibility: true, }); const entityA = { diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index e0b901855d..a0cdac70e8 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-common +## 1.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-search-common@1.2.19 + +## 1.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 1.1.4 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 17e631a547..7ce4e23d55 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-common", - "version": "1.1.4", + "version": "1.1.5", "description": "Common functionalities for the catalog plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 3b55716ecc..acb042aafa 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-catalog-graph +## 0.4.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.4.21 + +### Patch Changes + +- fe1a2f4: Catalog graph plugin support i18n +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.4.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.4.21-next.0 + +### Patch Changes + +- fe1a2f4: Catalog graph plugin support i18n +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + ## 0.4.20 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 019ce8421d..7b3a9e9487 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.20", + "version": "0.4.22-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 1fb4f81f6d..2ae3d85ea3 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-catalog-import +## 0.13.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.13.3 + +### Patch Changes + +- 406b8b8: Fixed bug with error message since ResponseError is now thrown from CatalogClient +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-catalog-common@1.1.5 + +## 0.13.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.13.2-next.0 + +### Patch Changes + +- 406b8b8: Fixed bug with error message since ResponseError is now thrown from CatalogClient +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/integration-react@1.2.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.13.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 5598f2930c..83c6e62f7c 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.1", + "version": "0.13.4-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 648648167d..08bfc0e35e 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-node +## 1.17.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 1.17.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + ## 1.17.1 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 3bf8741b08..d1984347ef 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.17.1", + "version": "1.17.2", "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 8ed8a2059b..779bf3a215 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,74 @@ # @backstage/plugin-catalog-react +## 1.19.2-next.0 + +### Patch Changes + +- 77eebdc: Support `filter` parameter on the `EntityHeaderBlueprint` +- a3a878d: Adding `type` as an override to the `convertLegacyEntityCardExtension` +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/frontend-test-utils@0.3.5-next.0 + +## 1.19.1 + +### Patch Changes + +- a07feb7: Fixed a but in the new alpha entity predicates where the `$in` operator mistakenly case sensitive. +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration-react@1.2.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/frontend-test-utils@0.3.4 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + +## 1.19.1-next.1 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/frontend-test-utils@0.3.4-next.1 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.19.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.9-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/frontend-test-utils@0.3.4-next.0 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.35 + ## 1.19.0 ### Minor Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 401067ca9b..bbfd1be6c7 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.19.0", + "version": "1.19.2-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 36a93a8a5e..1db7a8e5e4 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -95,6 +95,7 @@ export function convertLegacyEntityCardExtension( overrides?: { name?: string; filter?: string | EntityPredicate | ((entity: Entity) => boolean); + type?: EntityCardType; }, ): ExtensionDefinition; @@ -371,18 +372,43 @@ export const EntityHeaderBlueprint: ExtensionBlueprint<{ name: undefined; params: { loader: () => Promise; + filter?: EntityPredicate | ((entity: Entity) => boolean); }; - output: ConfigurableExtensionDataRef< - JSX_2.Element, - 'core.reactElement', - { - optional: true; - } - >; + output: + | ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + string, + 'catalog.entity-filter-expression', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + { + optional: true; + } + >; inputs: {}; - config: {}; - configInput: {}; + config: { + filter: EntityPredicate | undefined; + }; + configInput: { + filter?: EntityPredicate | undefined; + }; dataRefs: { + filterFunction: ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + {} + >; element: ConfigurableExtensionDataRef< JSX_2.Element, 'core.reactElement', diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.ts b/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.ts index dbfb11092a..4ff9d83282 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.ts +++ b/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.ts @@ -27,7 +27,7 @@ import { entityContentGroupDataRef, defaultEntityContentGroups, } from './extensionData'; -import { EntityPredicate } from '../predicates'; +import { EntityPredicate } from '../predicates/types'; import { resolveEntityFilterData } from './resolveEntityFilterData'; import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; import { Entity } from '@backstage/catalog-model'; diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityContentLayoutBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityContentLayoutBlueprint.tsx index e529d60685..c13ea8ad56 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityContentLayoutBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityContentLayoutBlueprint.tsx @@ -25,7 +25,7 @@ import { EntityCardType, } from './extensionData'; import { JSX } from 'react'; -import { EntityPredicate } from '../predicates'; +import { EntityPredicate } from '../predicates/types'; import { resolveEntityFilterData } from './resolveEntityFilterData'; import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; import { Entity } from '@backstage/catalog-model'; diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.tsx index 470aa13646..4b9b166196 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.tsx @@ -24,10 +24,8 @@ import MenuItem from '@material-ui/core/MenuItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; import { useEntityContextMenu } from '../../hooks/useEntityContextMenu'; -import { - EntityPredicate, - entityPredicateToFilterFunction, -} from '../predicates'; +import { EntityPredicate } from '../predicates/types'; +import { entityPredicateToFilterFunction } from '../predicates/entityPredicateToFilterFunction'; import type { Entity } from '@backstage/catalog-model'; import { entityFilterFunctionDataRef } from './extensionData'; import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx index 431197e753..b83136dcd9 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx @@ -19,22 +19,44 @@ import { coreExtensionData, ExtensionBoundary, } from '@backstage/frontend-plugin-api'; +import { EntityPredicate } from '../predicates/types'; +import { Entity } from '@backstage/catalog-model'; +import { resolveEntityFilterData } from './resolveEntityFilterData'; +import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; +import { + entityFilterExpressionDataRef, + entityFilterFunctionDataRef, +} from './extensionData'; /** @alpha */ export const EntityHeaderBlueprint = createExtensionBlueprint({ kind: 'entity-header', - attachTo: { id: 'page:catalog/entity', input: 'header' }, + attachTo: { id: 'page:catalog/entity', input: 'headers' }, dataRefs: { + filterFunction: entityFilterFunctionDataRef, element: coreExtensionData.reactElement, }, - output: [coreExtensionData.reactElement.optional()], + config: { + schema: { + filter: z => createEntityPredicateSchema(z).optional(), + }, + }, + output: [ + entityFilterFunctionDataRef.optional(), + entityFilterExpressionDataRef.optional(), + coreExtensionData.reactElement.optional(), + ], *factory( params: { loader: () => Promise; + filter?: EntityPredicate | ((entity: Entity) => boolean); }, - { node }, + { node, config }, ) { - const { loader } = params; + const { loader, filter } = params; + + yield* resolveEntityFilterData(filter, config, node); + if (loader) { yield coreExtensionData.reactElement( ExtensionBoundary.lazy(node, loader), diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityIconLinkBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityIconLinkBlueprint.tsx index 11c9a2b805..2368945c65 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityIconLinkBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityIconLinkBlueprint.tsx @@ -20,7 +20,7 @@ import { createExtensionDataRef, } from '@backstage/frontend-plugin-api'; -import { EntityPredicate } from '../predicates'; +import { EntityPredicate } from '../predicates/types'; import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; import { diff --git a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.test.tsx b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.test.tsx index 9e97412f92..fc7bed6281 100644 --- a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.test.tsx +++ b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.test.tsx @@ -26,7 +26,7 @@ import { import { screen } from '@testing-library/react'; import { convertLegacyEntityCardExtension } from './convertLegacyEntityCardExtension'; import { convertLegacyRouteRef } from '@backstage/core-compat-api'; -import { EntityContentBlueprint } from '../blueprints'; +import { EntityCardBlueprint } from '../blueprints'; const routeRef = createLegacyRouteRef({ id: 'test' }); const legacyPlugin = createLegacyPlugin({ @@ -60,12 +60,14 @@ describe('convertLegacyEntityCardExtension', () => { await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); - expect(tester.get(EntityContentBlueprint.dataRefs.filterExpression)).toBe( + expect(tester.get(EntityCardBlueprint.dataRefs.filterExpression)).toBe( undefined, ); - expect(tester.get(EntityContentBlueprint.dataRefs.filterFunction)).toBe( + expect(tester.get(EntityCardBlueprint.dataRefs.filterFunction)).toBe( undefined, ); + + expect(tester.get(EntityCardBlueprint.dataRefs.type)).toBe(undefined); }); it('should convert an entity card extension with overrides', async () => { @@ -94,10 +96,10 @@ describe('convertLegacyEntityCardExtension', () => { await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); - expect(tester.get(EntityContentBlueprint.dataRefs.filterExpression)).toBe( + expect(tester.get(EntityCardBlueprint.dataRefs.filterExpression)).toBe( 'my-filter', ); - expect(tester.get(EntityContentBlueprint.dataRefs.filterFunction)).toBe( + expect(tester.get(EntityCardBlueprint.dataRefs.filterFunction)).toBe( undefined, ); }); @@ -123,4 +125,32 @@ describe('convertLegacyEntityCardExtension', () => { expect(getDiscoveredId('EntityExAmpleCard')).toBe('entity-card:ex-ample'); expect(getDiscoveredId('ExampleCard')).toBe('entity-card:example-card'); }); + + it('should support the type override', async () => { + const LegacyExtension = legacyPlugin.provide( + createRoutableExtension({ + name: 'EntityExampleCard', + mountPoint: routeRef, + component: async () => () =>
Hello
, + }), + ); + + const converted = convertLegacyEntityCardExtension(LegacyExtension, { + type: 'info', + }); + + const tester = createExtensionTester(converted); + + expect(tester.query(converted).node.spec.id).toBe('entity-card:example'); + + await renderInTestApp(tester.reactElement(), { + mountedRoutes: { + '/': convertLegacyRouteRef(routeRef), + }, + }); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + + expect(tester.get(EntityCardBlueprint.dataRefs.type)).toBe('info'); + }); }); diff --git a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.tsx b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.tsx index 2a5dc115d4..9b343db469 100644 --- a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.tsx +++ b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityCardExtension.tsx @@ -18,10 +18,11 @@ import { compatWrapper } from '@backstage/core-compat-api'; import { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; -import { EntityCardBlueprint } from '../blueprints'; +import { EntityCardBlueprint } from '../blueprints/EntityCardBlueprint'; import kebabCase from 'lodash/kebabCase'; -import { EntityPredicate } from '../predicates'; +import { EntityPredicate } from '../predicates/types'; import { Entity } from '@backstage/catalog-model'; +import { EntityCardType } from '../blueprints/extensionData'; /** @alpha */ export function convertLegacyEntityCardExtension( @@ -29,6 +30,7 @@ export function convertLegacyEntityCardExtension( overrides?: { name?: string; filter?: string | EntityPredicate | ((entity: Entity) => boolean); + type?: EntityCardType; }, ): ExtensionDefinition { const element = ; @@ -63,6 +65,7 @@ export function convertLegacyEntityCardExtension( params: { filter: overrides?.filter, loader: async () => compatWrapper(element), + type: overrides?.type, }, }); } diff --git a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityContentExtension.tsx b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityContentExtension.tsx index 740427e9b5..719eb9c6d5 100644 --- a/plugins/catalog-react/src/alpha/converters/convertLegacyEntityContentExtension.tsx +++ b/plugins/catalog-react/src/alpha/converters/convertLegacyEntityContentExtension.tsx @@ -27,8 +27,8 @@ import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import kebabCase from 'lodash/kebabCase'; import startCase from 'lodash/startCase'; import { ComponentType } from 'react'; -import { EntityContentBlueprint } from '../blueprints'; -import { EntityPredicate } from '../predicates'; +import { EntityContentBlueprint } from '../blueprints/EntityContentBlueprint'; +import { EntityPredicate } from '../predicates/types'; import { Entity } from '@backstage/catalog-model'; /** @alpha */ diff --git a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts index 9e5f44b327..cfd2e451df 100644 --- a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts +++ b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EntityPredicate, EntityPredicateValue } from '.'; +import { EntityPredicate, EntityPredicateValue } from './types'; import type { z as zImpl, ZodType } from 'zod'; /** @internal */ diff --git a/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.test.ts b/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.test.ts index c83b213970..152230de7c 100644 --- a/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.test.ts +++ b/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.test.ts @@ -149,6 +149,8 @@ describe('entityPredicateToFilterFunction', () => { ['s,w,g,a', Object.create({ kind: 'component' })], ['', { 'metadata.tags': { $contains: 'go' } }], ['', { 'metadata.tags.0': 'java' }], + ['s,w,g', { kind: { $in: ['component', 'group'] } }], + ['a', { $not: { kind: { $in: ['component', 'group'] } } }], ['w,g,a', { $not: { 'metadata.tags': { $contains: 'java' } } }], [ 's,g', diff --git a/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.ts b/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.ts index 2fa220e9e2..f223911992 100644 --- a/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.ts +++ b/plugins/catalog-react/src/alpha/predicates/entityPredicateToFilterFunction.ts @@ -15,11 +15,7 @@ */ import { JsonValue } from '@backstage/types'; -import { - EntityPredicate, - EntityPredicatePrimitive, - EntityPredicateValue, -} from './types'; +import { EntityPredicate, EntityPredicateValue } from './types'; import { valueAtPath } from './valueAtPath'; /** @@ -92,7 +88,7 @@ function evaluatePredicateValue( return value.some(v => evaluateEntityPredicate(filter.$contains, v)); } if ('$in' in filter) { - return filter.$in.includes(value as EntityPredicatePrimitive); + return filter.$in.some(search => valuesAreEqual(value, search)); } if ('$exists' in filter) { if (filter.$exists === true) { diff --git a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md index 0bed34b2e0..d72fea4dd6 100644 --- a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-unprocessed-entities-common +## 0.0.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + +## 0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + ## 0.0.8 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities-common/package.json b/plugins/catalog-unprocessed-entities-common/package.json index 5bbe80a78a..6663c2535d 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.8", + "version": "0.0.9", "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 407c1599b4..301c9794d9 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 45fcc6f9a1..f0a8f31d35 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.18", + "version": "0.2.20-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 0b74c17faa..92c52e7329 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,96 @@ # @backstage/plugin-catalog +## 1.31.2-next.0 + +### Patch Changes + +- f4622e8: Adding a more sensible default order to the default filters +- 77eebdc: Support multiple headers in new frontend system, and don't render a header until the entity has finished loading +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-search-react@1.9.2 + +## 1.31.1 + +### Patch Changes + +- 6991dab: Turn on `pagination` by default in new frontend system, and also make configurable +- 3ab9b96: Updated card extensions for the new frontend system to use the new entity predicates, and to not show the about card on User and Group pages. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration-react@1.2.9 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-search-react@1.9.2 + - @backstage/plugin-techdocs-react@1.3.1 + +## 1.31.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.2 + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + +## 1.31.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-techdocs-react@1.3.1-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.31.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/plugin-search-react@1.9.2-next.0 + - @backstage/plugin-techdocs-react@1.3.1-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.31.0 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index f9f9e4f95d..35c49ec233 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.31.0", + "version": "1.31.2-next.0", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index 4be914a69d..81ebd10c3b 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -1012,9 +1012,26 @@ const _default: FrontendPlugin< }>; 'page:catalog': ExtensionDefinition<{ config: { + pagination: + | boolean + | { + mode: 'offset' | 'cursor'; + offset?: number | undefined; + limit?: number | undefined; + }; + } & { path: string | undefined; }; configInput: { + pagination?: + | boolean + | { + mode: 'offset' | 'cursor'; + offset?: number | undefined; + limit?: number | undefined; + } + | undefined; + } & { path?: string | undefined; }; output: @@ -1080,17 +1097,24 @@ const _default: FrontendPlugin< } >; inputs: { - header: ExtensionInput< - ConfigurableExtensionDataRef< - JSX_2.Element, - 'core.reactElement', - { - optional: true; - } - >, + headers: ExtensionInput< + | ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + { + optional: true; + } + >, { - singleton: true; - optional: true; + singleton: false; + optional: false; } >; contents: ExtensionInput< diff --git a/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx index 750c8567ee..8f5838d545 100644 --- a/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx @@ -102,13 +102,21 @@ export const EntityLayout = (props: EntityLayoutProps) => { UNSTABLE_contextMenuOptions, contextMenuItems, children, - header, NotFoundComponent, parentEntityRelations, } = props; const { kind } = useRouteRefParams(entityRouteRef); const { entity, loading, error } = useAsyncEntity(); + const header = props.header ?? ( + + ); + const routes = useElementFilter( children, elements => @@ -142,14 +150,7 @@ export const EntityLayout = (props: EntityLayoutProps) => { return ( - {header ?? ( - - )} + {!loading && header} {loading && } diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index 3913f8b2b7..f99c5961a1 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -56,6 +56,11 @@ export const catalogAboutEntityCard = EntityCardBlueprint.makeWithOverrides({ } return originalFactory({ type: 'info', + filter: { + $not: { + kind: { $in: ['user', 'group'] }, + }, + }, async loader() { const { InternalAboutCard } = await import( '../components/AboutCard/AboutCard' @@ -72,7 +77,7 @@ export const catalogLinksEntityCard = EntityCardBlueprint.make({ name: 'links', params: { type: 'info', - filter: 'has:links', + filter: { 'metadata.links': { $exists: true } }, loader: async () => import('../components/EntityLinksCard').then(m => compatWrapper(), @@ -84,7 +89,7 @@ export const catalogLabelsEntityCard = EntityCardBlueprint.make({ name: 'labels', params: { type: 'info', - filter: 'has:labels', + filter: { 'metadata.labels': { $exists: true } }, loader: async () => import('../components/EntityLabelsCard').then(m => compatWrapper(), @@ -95,7 +100,7 @@ export const catalogLabelsEntityCard = EntityCardBlueprint.make({ export const catalogDependsOnComponentsEntityCard = EntityCardBlueprint.make({ name: 'depends-on-components', params: { - filter: 'kind:component', + filter: { kind: 'component' }, loader: async () => import('../components/DependsOnComponentsCard').then(m => compatWrapper(), @@ -106,7 +111,7 @@ export const catalogDependsOnComponentsEntityCard = EntityCardBlueprint.make({ export const catalogDependsOnResourcesEntityCard = EntityCardBlueprint.make({ name: 'depends-on-resources', params: { - filter: 'kind:component', + filter: { kind: 'component' }, loader: async () => import('../components/DependsOnResourcesCard').then(m => compatWrapper(), @@ -117,7 +122,7 @@ export const catalogDependsOnResourcesEntityCard = EntityCardBlueprint.make({ export const catalogHasComponentsEntityCard = EntityCardBlueprint.make({ name: 'has-components', params: { - filter: 'kind:system', + filter: { kind: 'system' }, loader: async () => import('../components/HasComponentsCard').then(m => compatWrapper(), @@ -128,7 +133,7 @@ export const catalogHasComponentsEntityCard = EntityCardBlueprint.make({ export const catalogHasResourcesEntityCard = EntityCardBlueprint.make({ name: 'has-resources', params: { - filter: 'kind:system', + filter: { kind: 'system' }, loader: async () => import('../components/HasResourcesCard').then(m => compatWrapper(), @@ -139,7 +144,7 @@ export const catalogHasResourcesEntityCard = EntityCardBlueprint.make({ export const catalogHasSubcomponentsEntityCard = EntityCardBlueprint.make({ name: 'has-subcomponents', params: { - filter: 'kind:component', + filter: { kind: 'component' }, loader: async () => import('../components/HasSubcomponentsCard').then(m => compatWrapper(), @@ -150,7 +155,7 @@ export const catalogHasSubcomponentsEntityCard = EntityCardBlueprint.make({ export const catalogHasSubdomainsEntityCard = EntityCardBlueprint.make({ name: 'has-subdomains', params: { - filter: 'kind:domain', + filter: { kind: 'domain' }, loader: async () => import('../components/HasSubdomainsCard').then(m => compatWrapper(), @@ -161,7 +166,7 @@ export const catalogHasSubdomainsEntityCard = EntityCardBlueprint.make({ export const catalogHasSystemsEntityCard = EntityCardBlueprint.make({ name: 'has-systems', params: { - filter: 'kind:domain', + filter: { kind: 'domain' }, loader: async () => import('../components/HasSystemsCard').then(m => compatWrapper(), diff --git a/plugins/catalog/src/alpha/filters.tsx b/plugins/catalog/src/alpha/filters.tsx index fcfbc394f2..d72e299fbb 100644 --- a/plugins/catalog/src/alpha/filters.tsx +++ b/plugins/catalog/src/alpha/filters.tsx @@ -133,13 +133,14 @@ const catalogListCatalogFilter = CatalogFilterBlueprint.makeWithOverrides({ }, }); +// this is the default order that the filters will be applied in export default [ - catalogTagCatalogFilter, catalogKindCatalogFilter, catalogTypeCatalogFilter, - catalogModeCatalogFilter, - catalogNamespaceCatalogFilter, - catalogLifecycleCatalogFilter, - catalogProcessingStatusCatalogFilter, catalogListCatalogFilter, + catalogModeCatalogFilter, + catalogLifecycleCatalogFilter, + catalogTagCatalogFilter, + catalogProcessingStatusCatalogFilter, + catalogNamespaceCatalogFilter, ]; diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index c1f5b55341..f0c5316a84 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -41,7 +41,22 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ inputs: { filters: createExtensionInput([coreExtensionData.reactElement]), }, - factory(originalFactory, { inputs }) { + config: { + schema: { + pagination: z => + z + .union([ + z.boolean(), + z.object({ + mode: z.enum(['cursor', 'offset']), + limit: z.number().optional(), + offset: z.number().optional(), + }), + ]) + .default(true), + }, + }, + factory(originalFactory, { inputs, config }) { return originalFactory({ defaultPath: '/catalog', routeRef: convertLegacyRouteRef(rootRouteRef), @@ -50,7 +65,12 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ const filters = inputs.filters.map(filter => filter.get(coreExtensionData.reactElement), ); - return compatWrapper({filters}} />); + return compatWrapper( + {filters}} + pagination={config.pagination} + />, + ); }, }); }, @@ -59,10 +79,10 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ name: 'entity', inputs: { - header: createExtensionInput( - [EntityHeaderBlueprint.dataRefs.element.optional()], - { singleton: true, optional: true }, - ), + headers: createExtensionInput([ + EntityHeaderBlueprint.dataRefs.element.optional(), + EntityHeaderBlueprint.dataRefs.filterFunction.optional(), + ]), contents: createExtensionInput([ coreExtensionData.reactElement, coreExtensionData.routePath, @@ -104,9 +124,19 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ { title: string; items: Array<(typeof inputs.contents)[0]> } >; - const header = inputs.header?.get( - EntityHeaderBlueprint.dataRefs.element, - ); + // Get available headers, sorted by if they have a filter function or not. + // TODO(blam): we should really have priority or some specificity here which can be used to sort the headers. + // That can be done with embedding the priority in the dataRef alongside the filter function. + const headers = inputs.headers + .map(header => ({ + element: header.get(EntityHeaderBlueprint.dataRefs.element), + filter: header.get(EntityHeaderBlueprint.dataRefs.filterFunction), + })) + .sort((a, b) => { + if (a.filter && !b.filter) return -1; + if (!a.filter && b.filter) return 1; + return 0; + }); let groups = Object.entries(defaultEntityContentGroups).reduce( (rest, group) => { @@ -149,6 +179,10 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ ? menuItems.filter(i => i.filter(entity)).map(i => i.element) : []; + const header = headers.find( + h => !h.filter || h.filter(entity!), + )?.element; + return ( ` component +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/core-app-api@1.18.0 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-home-react@0.1.28 + +## 0.8.10-next.2 + +### Patch Changes + +- d52d67f: Added a New Frontend System App Root Element for the `` component +- Updated dependencies + - @backstage/theme@0.6.7-next.1 + - @backstage/core-app-api@1.18.0-next.1 + - @backstage/core-components@0.17.4-next.2 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + +## 0.8.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-app-api@1.17.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + - @backstage/plugin-home-react@0.1.28-next.1 + +## 0.8.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-home-react@0.1.28-next.0 + ## 0.8.9 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 203a670ed9..88ef031c08 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.8.9", + "version": "0.8.11-next.0", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/home/report-alpha.api.md b/plugins/home/report-alpha.api.md index f36589ea51..98a8cab823 100644 --- a/plugins/home/report-alpha.api.md +++ b/plugins/home/report-alpha.api.md @@ -19,6 +19,21 @@ const _default: FrontendPlugin< }, {}, { + 'app-root-element:home/visit-listener': ExtensionDefinition<{ + kind: 'app-root-element'; + name: 'visit-listener'; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + {} + >; + inputs: {}; + params: { + element: JSX.Element | (() => JSX.Element); + }; + }>; 'page:home': ExtensionDefinition<{ config: { path: string | undefined; diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index fc34c6e806..880b53af40 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -21,8 +21,10 @@ import { PageBlueprint, createFrontendPlugin, createRouteRef, + AppRootElementBlueprint, } from '@backstage/frontend-plugin-api'; import { compatWrapper } from '@backstage/core-compat-api'; +import { VisitListener } from './components/'; const rootRouteRef = createRouteRef(); @@ -63,13 +65,20 @@ const homePage = PageBlueprint.makeWithOverrides({ }, }); +const visitListenerAppRootElement = AppRootElementBlueprint.make({ + name: 'visit-listener', + params: { + element: , + }, +}); + /** * @alpha */ export default createFrontendPlugin({ pluginId: 'home', info: { packageJson: () => import('../package.json') }, - extensions: [homePage], + extensions: [homePage, visitListenerAppRootElement], routes: { root: rootRouteRef, }, diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 656321d450..3891571a4f 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-kubernetes-backend +## 0.19.8 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-kubernetes-node@0.3.2 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 0.19.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-kubernetes-node@0.3.2-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration-aws-node@0.1.17-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + ## 0.19.7 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 820804974a..27416f70ce 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.19.7", + "version": "0.19.8", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index fef1236d13..35f0f0c651 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + +## 0.0.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-kubernetes-common@0.9.6 + - @backstage/plugin-kubernetes-react@0.5.9 + - @backstage/plugin-permission-react@0.4.36 + +## 0.0.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + - @backstage/plugin-kubernetes-react@0.5.9-next.1 + +## 0.0.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-kubernetes-react@0.5.9-next.0 + - @backstage/plugin-permission-react@0.4.35 + ## 0.0.26 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 634532e6df..50223918fa 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.26", + "version": "0.0.28-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 d9c4ff3c5b..64ea6455e4 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-kubernetes-common +## 0.9.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + +## 0.9.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + ## 0.9.5 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 1a5266a280..cde58de050 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.5", + "version": "0.9.6", "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 c11e7078e2..03d426e71d 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-node +## 0.3.2 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 0.3.2-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + ## 0.3.1 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 2a0997fa44..d9d152fda6 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.3.1", + "version": "0.3.2", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-node/report.api.md b/plugins/kubernetes-node/report.api.md index af0c2c599a..5758db9ea1 100644 --- a/plugins/kubernetes-node/report.api.md +++ b/plugins/kubernetes-node/report.api.md @@ -5,7 +5,6 @@ ```ts import { AuthenticationStrategy as AuthenticationStrategy_2 } from '@backstage/plugin-kubernetes-node'; import { BackstageCredentials } from '@backstage/backend-plugin-api'; -import { ClusterDetails as ClusterDetails_2 } from '@backstage/plugin-kubernetes-node'; import { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; import { Entity } from '@backstage/catalog-model'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; @@ -256,7 +255,7 @@ export class PinnipedHelper { constructor(logger: LoggerService); // (undocumented) tokenCredentialRequest( - clusterDetails: ClusterDetails_2, + clusterDetails: ClusterDetails, pinnipedParams: PinnipedParameters, ): Promise; } diff --git a/plugins/kubernetes-node/src/auth/PinnipedHelper.ts b/plugins/kubernetes-node/src/auth/PinnipedHelper.ts index 39421ecd62..d6c39d55de 100644 --- a/plugins/kubernetes-node/src/auth/PinnipedHelper.ts +++ b/plugins/kubernetes-node/src/auth/PinnipedHelper.ts @@ -15,9 +15,9 @@ */ import { LoggerService } from '@backstage/backend-plugin-api'; -import { ClusterDetails } from '@backstage/plugin-kubernetes-node'; import * as https from 'https'; import fetch, { RequestInit } from 'node-fetch'; +import { ClusterDetails } from '../types/types'; /** * diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index aed2c7522e..fc3417e825 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-kubernetes-react +## 0.5.9 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 0.5.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.5.8 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 7050a19f36..7cb8e4a9ce 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.8", + "version": "0.5.9", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index fe906bc2a1..7a98455d12 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-kubernetes +## 0.12.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.12.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-kubernetes-common@0.9.6 + - @backstage/plugin-kubernetes-react@0.5.9 + - @backstage/plugin-permission-react@0.4.36 + +## 0.12.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-kubernetes-common@0.9.6-next.0 + - @backstage/plugin-kubernetes-react@0.5.9-next.1 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.12.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-kubernetes-react@0.5.9-next.0 + - @backstage/plugin-permission-react@0.4.35 + ## 0.12.8 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index e8e9c1b867..d280012e16 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.12.8", + "version": "0.12.10-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 a00d07bda8..60f0a430e2 100644 --- a/plugins/mcp-actions-backend/CHANGELOG.md +++ b/plugins/mcp-actions-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-mcp-actions-backend +## 0.1.1 + +### Patch Changes + +- 6bc0799: Fixed the example in the README for generating a static token by adding a subject field +- Updated dependencies + - @backstage/backend-defaults@0.11.1 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.1.1-next.0 + +### Patch Changes + +- 6bc0799: Fixed the example in the README for generating a static token by adding a subject field +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/catalog-client@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.1.0 ### Minor Changes diff --git a/plugins/mcp-actions-backend/package.json b/plugins/mcp-actions-backend/package.json index 72064a3490..3fdfb04e42 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.0", + "version": "0.1.1", "backstage": { "role": "backend-plugin", "pluginId": "mcp-actions", diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 98d6646b1d..31f004d9ab 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.11 + +### Patch Changes + +- f92c9fc: Add optional config for `ses` mail options with `sourceArn`, `fromArn`, `configurationSetName` +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-notifications-node@0.2.17 + +## 0.3.11-next.1 + +### Patch Changes + +- f92c9fc: Add optional config for `ses` mail options with `sourceArn`, `fromArn`, `configurationSetName` + +## 0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration-aws-node@0.1.17-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-notifications-node@0.2.17-next.0 + ## 0.3.10 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/README.md b/plugins/notifications-backend-module-email/README.md index ed5bc22af3..c1ead48876 100644 --- a/plugins/notifications-backend-module-email/README.md +++ b/plugins/notifications-backend-module-email/README.md @@ -79,6 +79,11 @@ notifications: # Who to send email for broadcast notifications broadcastConfig: receiver: 'users' + # Optional SES config + # sesConfig: + # sourceArn: 'arn:aws:ses:us-west-2:123456789012:identity/example.com' + # fromArn: 'arn:aws:ses:us-west-2:123456789012:identity/example.com' + # configurationSetName: 'custom-config' # How many emails to send concurrently, defaults to 2 concurrencyLimit: 10 # How much to throttle between emails, defaults to 100ms diff --git a/plugins/notifications-backend-module-email/config.d.ts b/plugins/notifications-backend-module-email/config.d.ts index 97a6495246..7116826c5d 100644 --- a/plugins/notifications-backend-module-email/config.d.ts +++ b/plugins/notifications-backend-module-email/config.d.ts @@ -132,6 +132,23 @@ export interface Config { */ receiverEmails?: string[]; }; + /** + * Optional SES config for mail options. Allows for delegated sender + */ + sesConfig?: { + /** + * ARN of the identity to use as the source of the email + */ + sourceArn?: string; + /** + * ARN of the identity to use for the "From"/sender address of the email + */ + fromArn?: string; + /** + * Name of the configuration set to use when sending email via ses + */ + configurationSetName?: string; + }; cache?: { /** * Email cache TTL, defaults to 1 hour diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index 33efc60e35..87bd01e5a8 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.10", + "version": "0.3.11", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.test.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.test.ts index 1408abcf9c..ebe1b90f35 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.test.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.test.ts @@ -442,4 +442,64 @@ describe('NotificationsEmailProcessor', () => { to: 'mock@backstage.io', }); }); + + it('should send email with ses config', async () => { + const SES_SENDMAIL_CONFIG = { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + email: { + transportConfig: { + transport: 'ses', + region: 'us-west-2', + }, + sender: 'backstage@backstage.io', + replyTo: 'no-reply@backstage.io', + sesConfig: { + sourceArn: + 'arn:aws:ses:us-west-2:123456789012:identity/example.com', + fromArn: + 'arn:aws:ses:us-west-2:123456789012:identity/example.com', + }, + }, + }, + }, + }; + (createTransport as jest.Mock).mockReturnValue(mockTransport); + const processor = new NotificationsEmailProcessor( + logger, + mockServices.rootConfig({ data: SES_SENDMAIL_CONFIG }), + catalogServiceMock({ entities: [DEFAULT_ENTITIES_RESPONSE.items[0]] }), + auth, + ); + + await processor.postProcess( + { + origin: 'plugin', + id: '1234', + user: 'user:default/mock', + created: new Date(), + payload: { title: 'notification' }, + }, + { + recipients: { type: 'entity', entityRef: 'user:default/mock' }, + payload: { title: 'notification' }, + }, + ); + + expect(sendmailMock).toHaveBeenCalledWith({ + from: 'backstage@backstage.io', + html: '

https://example.org/notifications

', + replyTo: 'no-reply@backstage.io', + subject: 'notification', + text: 'https://example.org/notifications', + to: 'mock@backstage.io', + ses: { + 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/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts index 3496d431e3..39a0c5da02 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts @@ -52,6 +52,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { private readonly transportConfig: Config; private readonly sender: string; private readonly replyTo?: string; + private readonly sesConfig?: Config; private readonly cacheTtl: number; private readonly concurrencyLimit: number; private readonly throttleInterval: number; @@ -76,6 +77,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { emailProcessorConfig.getOptionalConfig('broadcastConfig'); this.sender = emailProcessorConfig.getString('sender'); this.replyTo = emailProcessorConfig.getOptionalString('replyTo'); + this.sesConfig = emailProcessorConfig.getOptionalConfig('sesConfig'); this.concurrencyLimit = emailProcessorConfig.getOptionalNumber('concurrencyLimit') ?? 2; this.throttleInterval = emailProcessorConfig.has('throttleInterval') @@ -292,6 +294,24 @@ export class NotificationsEmailProcessor implements NotificationProcessor { return contentParts.join('\n\n'); } + private async getSesOptions() { + if (!this.sesConfig) { + return undefined; + } + const ses: Record = {}; + const sourceArn = this.sesConfig.getOptionalString('sourceArn'); + const fromArn = this.sesConfig.getOptionalString('fromArn'); + const configurationSetName = this.sesConfig.getOptionalString( + 'configurationSetName', + ); + + if (sourceArn) ses.SourceArn = sourceArn; + if (fromArn) ses.FromArn = fromArn; + if (configurationSetName) ses.ConfigurationSetName = configurationSetName; + + return Object.keys(ses).length > 0 ? ses : undefined; + } + private async sendPlainEmail(notification: Notification, emails: string[]) { const mailOptions = { from: this.sender, @@ -299,6 +319,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { html: this.getHtmlContent(notification), text: this.getTextContent(notification), replyTo: this.replyTo, + ses: await this.getSesOptions(), }; await this.sendMails(mailOptions, emails); @@ -316,6 +337,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { html: await this.templateRenderer?.getHtml?.(notification), text: await this.templateRenderer?.getText?.(notification), replyTo: this.replyTo, + ses: await this.getSesOptions(), }; await this.sendMails(mailOptions, emails); diff --git a/plugins/notifications-backend-module-slack/CHANGELOG.md b/plugins/notifications-backend-module-slack/CHANGELOG.md index a72c7dc3bc..c91d4837d0 100644 --- a/plugins/notifications-backend-module-slack/CHANGELOG.md +++ b/plugins/notifications-backend-module-slack/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-notifications-backend-module-slack +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-notifications-node@0.2.17 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-notifications-node@0.2.17-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/notifications-backend-module-slack/package.json b/plugins/notifications-backend-module-slack/package.json index 9bb85918ff..5ce7157a88 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.1.2", + "version": "0.1.3", "description": "The slack backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index 98aa805d31..62fdaeee8e 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-notifications-backend +## 0.5.8 + +### Patch Changes + +- 4401dfb: Allow defining default notification settings via configuration +- 9a5a73f: Fix `addTopic` migration when `user_settings` present +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-notifications-node@0.2.17 + - @backstage/plugin-signals-node@0.1.22 + +## 0.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/plugin-signals-node@0.1.22-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-notifications-node@0.2.17-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 0.5.8-next.0 + +### Patch Changes + +- 9a5a73f: Fix `addTopic` migration when `user_settings` present +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-signals-node@0.1.21 + ## 0.5.7 ### Patch Changes diff --git a/plugins/notifications-backend/config.d.ts b/plugins/notifications-backend/config.d.ts index 61ae411df8..2b6f874f72 100644 --- a/plugins/notifications-backend/config.d.ts +++ b/plugins/notifications-backend/config.d.ts @@ -29,6 +29,22 @@ export interface Config { */ throttleInterval?: HumanDuration | string; /** + * Default settings for user specific notification settings + */ + defaultSettings?: { + channels?: { + id: string; + origins?: { + id: string; + enabled: boolean; + topics?: { + id: string; + enabled: boolean; + }[]; + }[]; + }[]; + }; + /* * Time to keep the notifications in the database, defaults to 365 days. * Can be disabled by setting to false. */ diff --git a/plugins/notifications-backend/migrations/20250317_addTopic.js b/plugins/notifications-backend/migrations/20250317_addTopic.js index c8f78a5640..e17b8d0789 100644 --- a/plugins/notifications-backend/migrations/20250317_addTopic.js +++ b/plugins/notifications-backend/migrations/20250317_addTopic.js @@ -18,14 +18,10 @@ const crypto = require('crypto'); exports.up = async function up(knex) { await knex.schema.alterTable('user_settings', table => { table.string('topic').nullable().after('origin'); - table.string('settings_key_hash', 64).notNullable(); + table.string('settings_key_hash', 64).nullable(); table.dropUnique([], 'user_settings_unique_idx'); }); - await knex.schema.alterTable('user_settings', table => { - table.unique(['settings_key_hash'], 'user_settings_unique_idx'); - }); - const rows = await knex('user_settings').select('user', 'channel', 'origin'); for (const row of rows) { const rawKey = `${row.user}|${row.channel}|${row.origin}|}`; @@ -35,10 +31,14 @@ exports.up = async function up(knex) { user: row.user, channel: row.channel, origin: row.origin, - topic: row.topic, }) .update({ settings_key_hash: hash }); } + + await knex.schema.alterTable('user_settings', table => { + table.string('settings_key_hash', 64).notNullable().alter(); + table.unique(['settings_key_hash'], 'user_settings_unique_idx'); + }); }; exports.down = async function down(knex) { diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index 9a1efaae84..2fac1a8cff 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.5.7", + "version": "0.5.8", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-backend/src/service/router.test.ts b/plugins/notifications-backend/src/service/router.test.ts index 1b3f2e8fd6..6c74fed41c 100644 --- a/plugins/notifications-backend/src/service/router.test.ts +++ b/plugins/notifications-backend/src/service/router.test.ts @@ -53,7 +53,24 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { const auth = mockServices.auth(); const config = mockServices.rootConfig({ - data: { app: { baseUrl: 'http://localhost' } }, + data: { + app: { baseUrl: 'http://localhost' }, + notifications: { + defaultSettings: { + channels: [ + { + id: 'Web', + origins: [ + { + id: 'external:test-service2', + enabled: false, + }, + ], + }, + ], + }, + }, + }, }); const catalog = catalogServiceMock({ @@ -314,6 +331,15 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { it('should not send to user entity if origin is disabled in settings', async () => { const client = await database.getClient(); + // Insert a notification with a origin + await client('notification').insert({ + id: uuid(), + user: 'user:default/mock', + origin: 'external:test-service', + title: 'Test notification', + created: new Date(), + severity: 'normal', + }); await client('user_settings').insert({ settings_key_hash: 'hash', user: 'user:default/mock', @@ -338,11 +364,22 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { const notifications = await client('notification') .where('user', 'user:default/mock') .select(); - expect(notifications).toHaveLength(0); + // This should not create a new notification since the origin is disabled + expect(notifications).toHaveLength(1); }); it('should not send to user entity if topic is disabled in settings', async () => { const client = await database.getClient(); + // Insert a notification with a topic + await client('notification').insert({ + id: uuid(), + user: 'user:default/mock', + origin: 'external:test-service', + topic: 'test-topic', + title: 'Test notification', + created: new Date(), + severity: 'normal', + }); await client('user_settings').insert({ settings_key_hash: 'hash', user: 'user:default/mock', @@ -369,7 +406,8 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { const notifications = await client('notification') .where('user', 'user:default/mock') .select(); - expect(notifications).toHaveLength(0); + // This should not create a new notification since the topic is disabled + expect(notifications).toHaveLength(1); }); it('should send to user entity if origin is enabled, but topic is disabled in settings', async () => { @@ -570,9 +608,30 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { jest.resetAllMocks(); const client = await database.getClient(); await client('user_settings').del(); + await client('notification').del(); + + await client('notification').insert({ + id: uuid(), + user: 'user:default/mock', + origin: 'external:test-service', + topic: 'test-topic', + title: 'Test notification', + created: new Date(), + severity: 'normal', + }); + + await client('notification').insert({ + id: uuid(), + user: 'user:default/mock', + origin: 'external:test-service2', + title: 'Test notification', + topic: 'test-topic2', + created: new Date(), + severity: 'normal', + }); }); - it('should return user settings', async () => { + it('should return origin settings correctly', async () => { const client = await database.getClient(); await client('user_settings').insert({ settings_key_hash: 'hash', @@ -588,9 +647,76 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { channels: [ { id: 'Web', - origins: [ - { enabled: false, id: 'external:test-service', topics: [] }, - ], + origins: expect.arrayContaining([ + { + enabled: false, + id: 'external:test-service', + topics: [{ enabled: false, id: 'test-topic' }], + }, + { + enabled: false, + id: 'external:test-service2', + topics: [{ enabled: false, id: 'test-topic2' }], + }, + ]), + }, + ], + }); + }); + + it('should return topic settings correctly', async () => { + const client = await database.getClient(); + await client('user_settings').insert({ + settings_key_hash: 'hash', + user: 'user:default/mock', + channel: 'Web', + origin: 'external:test-service', + topic: 'test-topic', + enabled: false, + }); + + const response = await request(app).get('/settings'); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + channels: [ + { + id: 'Web', + origins: expect.arrayContaining([ + { + enabled: true, + id: 'external:test-service', + topics: [{ enabled: false, id: 'test-topic' }], + }, + { + enabled: false, + id: 'external:test-service2', + topics: [{ enabled: false, id: 'test-topic2' }], + }, + ]), + }, + ], + }); + }); + + it('should return default user settings from config', async () => { + const response = await request(app).get('/settings'); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + channels: [ + { + id: 'Web', + origins: expect.arrayContaining([ + { + enabled: true, + id: 'external:test-service', + topics: [{ enabled: true, id: 'test-topic' }], + }, + { + enabled: false, + id: 'external:test-service2', + topics: [{ enabled: false, id: 'test-topic2' }], + }, + ]), }, ], }); diff --git a/plugins/notifications-backend/src/service/router.ts b/plugins/notifications-backend/src/service/router.ts index 9563d7965b..5805092096 100644 --- a/plugins/notifications-backend/src/service/router.ts +++ b/plugins/notifications-backend/src/service/router.ts @@ -97,6 +97,8 @@ export async function createRouter( limit: concurrencyLimit, interval: throttleInterval, }); + const defaultNotificationSettings: NotificationSettings | undefined = + config.getOptional('notifications.defaultSettings'); const getUser = async (req: Request) => { const credentials = await httpAuth.credentials(req, { allow: ['user'] }); @@ -104,61 +106,94 @@ export async function createRouter( return info.userEntityRef; }; + const getNotificationChannels = () => { + return [WEB_NOTIFICATION_CHANNEL, ...processors.map(p => p.getName())]; + }; + const getTopicSettings = ( topic: any, existingOrigin: OriginSetting | undefined, + defaultOriginSettings: OriginSetting | undefined, defaultEnabled: boolean, ) => { const existingTopic = existingOrigin?.topics?.find( - t => t.id === topic.topic, + t => t.id.toLowerCase() === topic.topic.toLowerCase(), ); + const defaultTopicSettings = defaultOriginSettings?.topics?.find( + t => t.id.toLowerCase() === topic.topic.toLowerCase(), + ); + return { id: topic.topic, - enabled: existingTopic ? existingTopic.enabled : defaultEnabled, + enabled: existingTopic + ? existingTopic.enabled + : defaultTopicSettings?.enabled ?? defaultEnabled, }; }; const getOriginSettings = ( originId: string, existingChannel: ChannelSetting | undefined, + defaultChannelSettings: ChannelSetting | undefined, topics: { origin: string; topic: string }[], ) => { - const existingOrigin = existingChannel?.origins.find( - o => o.id === originId, + const existingOrigin = existingChannel?.origins?.find( + o => o.id.toLowerCase() === originId.toLowerCase(), ); - const defaultEnabled = existingOrigin ? existingOrigin.enabled : true; + + const defaultOriginSettings = defaultChannelSettings?.origins?.find( + c => c.id.toLowerCase() === originId.toLowerCase(), + ); + + const defaultEnabled = existingOrigin + ? existingOrigin.enabled + : defaultOriginSettings?.enabled ?? true; + return { id: originId, enabled: defaultEnabled, topics: topics .filter(t => t.origin === originId) - .map(t => getTopicSettings(t, existingOrigin, defaultEnabled)), + .map(t => + getTopicSettings( + t, + existingOrigin, + defaultOriginSettings, + defaultEnabled, + ), + ), }; }; - const getNotificationChannels = () => { - return [WEB_NOTIFICATION_CHANNEL, ...processors.map(p => p.getName())]; - }; - const getChannelSettings = ( channelId: string, settings: NotificationSettings, origins: string[], topics: { origin: string; topic: string }[], ) => { - const existingChannel = settings.channels.find(c => c.id === channelId); - if (existingChannel) { - return existingChannel; - } + const existingChannel = settings.channels.find( + c => c.id.toLowerCase() === channelId.toLowerCase(), + ); + const defaultChannelSettings = defaultNotificationSettings?.channels?.find( + c => c.id.toLowerCase() === channelId.toLowerCase(), + ); + return { id: channelId, origins: origins.map(originId => - getOriginSettings(originId, existingChannel, topics), + getOriginSettings( + originId, + existingChannel, + defaultChannelSettings, + topics, + ), ), }; }; - const getNotificationSettings = async (user: string) => { + const getNotificationSettings = async ( + user: string, + ): Promise => { const { origins } = await store.getUserNotificationOrigins({ user }); const { topics } = await store.getUserNotificationTopics({ user }); const settings = await store.getNotificationSettings({ user }); diff --git a/plugins/notifications-backend/src/tests/migrations.test.ts b/plugins/notifications-backend/src/tests/migrations.test.ts new file mode 100644 index 0000000000..aa3ba7ae9a --- /dev/null +++ b/plugins/notifications-backend/src/tests/migrations.test.ts @@ -0,0 +1,99 @@ +/* + * 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 { Knex } from 'knex'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import fs from 'fs'; + +const migrationsDir = `${__dirname}/../../migrations`; +const migrationsFiles = fs.readdirSync(migrationsDir).sort(); + +async function migrateUpOnce(knex: Knex): Promise { + await knex.migrate.up({ directory: migrationsDir }); +} + +async function migrateDownOnce(knex: Knex): Promise { + await knex.migrate.down({ directory: migrationsDir }); +} + +async function migrateUntilBefore(knex: Knex, target: string): Promise { + const index = migrationsFiles.indexOf(target); + if (index === -1) { + throw new Error(`Migration ${target} not found`); + } + for (let i = 0; i < index; i++) { + await migrateUpOnce(knex); + } +} + +jest.setTimeout(60_000); + +describe('migrations', () => { + const databases = TestDatabases.create(); + + it.each(databases.eachSupportedId())( + '20221109192547_search_add_original_value_column.js, %p', + async databaseId => { + const knex = await databases.init(databaseId); + + await migrateUntilBefore(knex, '20250317_addTopic.js'); + + await knex + .insert({ + user: 'user1', + channel: 'channel1', + origin: 'origin1', + enabled: true, + }) + .into('user_settings'); + + await migrateUpOnce(knex); + + let rows = await knex('user_settings'); + let normalized = rows.map(r => ({ ...r, enabled: !!r.enabled })); + + expect(normalized).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + user: 'user1', + channel: 'channel1', + origin: 'origin1', + enabled: true, + settings_key_hash: + '73f97aff883b8b08a7f4e366234ef4f86827702b0016574ac4c1bf313c703d15', + topic: null, + }), + ]), + ); + + await migrateDownOnce(knex); + + rows = await knex('user_settings'); + normalized = rows.map(r => ({ ...r, enabled: !!r.enabled })); + + expect(normalized).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + user: 'user1', + channel: 'channel1', + origin: 'origin1', + enabled: true, + }), + ]), + ); + }, + ); +}); diff --git a/plugins/notifications-common/CHANGELOG.md b/plugins/notifications-common/CHANGELOG.md index 9e73b026f9..cd8ad5b094 100644 --- a/plugins/notifications-common/CHANGELOG.md +++ b/plugins/notifications-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-notifications-common +## 0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + +## 0.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + ## 0.0.9 ### Patch Changes diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index c47af28ddd..66473d0237 100644 --- a/plugins/notifications-common/package.json +++ b/plugins/notifications-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-common", - "version": "0.0.9", + "version": "0.0.10", "description": "Common functionalities for the notifications plugin", "backstage": { "role": "common-library", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 2ad8c1eefc..3ec241f5a6 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-notifications-node +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-signals-node@0.1.22 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/plugin-signals-node@0.1.22-next.0 + ## 0.2.16 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index 47e6947ace..2fb0ad577d 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.16", + "version": "0.2.17", "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 48cab7385c..64a6b3c67e 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-notifications +## 0.5.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.5.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-signals-react@0.0.15 + +## 0.5.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + - @backstage/plugin-signals-react@0.0.15-next.0 + +## 0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-signals-react@0.0.14 + ## 0.5.6 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 80bf36820b..819ef1e7cd 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.5.6", + "version": "0.5.8-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index f570e99ecb..141a642692 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-org-react +## 0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + +## 0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + +## 0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + +## 0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.8 + ## 0.1.39 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index c4531704a3..5290ef4d47 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.39", + "version": "0.1.41-next.0", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 79481c4512..6651ff0226 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-org +## 0.6.42-next.0 + +### Patch Changes + +- 43cbb10: Added OwnershipCard, ComponentsGrid and UserProfileCard components to the `overridableComponents`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.6.41 + +### Patch Changes + +- 3ab9b96: Updated card extensions for the new frontend system to use the new entity predicates, and switch the card type to `info` for the user and group profile cards. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-catalog-common@1.1.5 + +## 0.6.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 0.6.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.6.40 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 1d430267be..90a2dc3c0a 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.40", + "version": "0.6.42-next.0", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/org/report.api.md b/plugins/org/report.api.md index 906e43a785..7d58d96263 100644 --- a/plugins/org/report.api.md +++ b/plugins/org/report.api.md @@ -9,6 +9,13 @@ import { IconComponent } from '@backstage/core-plugin-api'; import { InfoCardVariants } from '@backstage/core-components'; import { JSX as JSX_2 } from 'react/jsx-runtime'; +// @public (undocumented) +export type ComponentsGridClassKey = + | 'card' + | 'bold' + | 'smallFont' + | 'entityTypeBox'; + // @public (undocumented) export const EntityGroupProfileCard: (props: { variant?: InfoCardVariants; @@ -96,6 +103,15 @@ export const OwnershipCard: (props: { entityLimit?: number; }) => JSX_2.Element; +// @public (undocumented) +export type OwnershipCardClassKey = + | 'card' + | 'cardContent' + | 'list' + | 'listItemText' + | 'listItemSecondaryAction' + | 'grid'; + // @public (undocumented) export const UserProfileCard: (props: { variant?: InfoCardVariants; @@ -103,4 +119,10 @@ export const UserProfileCard: (props: { maxRelations?: number; hideIcons?: boolean; }) => JSX_2.Element; + +// @public (undocumented) +export type UserProfileCardClassKey = + | 'closeButton' + | 'moreButton' + | 'dialogPaper'; ``` diff --git a/plugins/org/src/alpha.tsx b/plugins/org/src/alpha.tsx index e5d6aa6675..92ae7d8801 100644 --- a/plugins/org/src/alpha.tsx +++ b/plugins/org/src/alpha.tsx @@ -26,7 +26,8 @@ import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; const EntityGroupProfileCard = EntityCardBlueprint.make({ name: 'group-profile', params: { - filter: 'kind:group', + type: 'info', + filter: { kind: 'group' }, loader: async () => import('./components/Cards/Group/GroupProfile/GroupProfileCard').then(m => compatWrapper(), @@ -38,7 +39,7 @@ const EntityGroupProfileCard = EntityCardBlueprint.make({ const EntityMembersListCard = EntityCardBlueprint.make({ name: 'members-list', params: { - filter: 'kind:group', + filter: { kind: 'group' }, loader: async () => import('./components/Cards/Group/MembersList/MembersListCard').then(m => compatWrapper(), @@ -50,7 +51,7 @@ const EntityMembersListCard = EntityCardBlueprint.make({ const EntityOwnershipCard = EntityCardBlueprint.make({ name: 'ownership', params: { - filter: 'kind:group,user', + filter: { kind: { $in: ['group', 'user'] } }, loader: async () => import('./components/Cards/OwnershipCard/OwnershipCard').then(m => compatWrapper(), @@ -69,7 +70,8 @@ const EntityUserProfileCard = EntityCardBlueprint.makeWithOverrides({ }, factory(originalFactory, { config }) { return originalFactory({ - filter: 'kind:user', + type: 'info', + filter: { kind: 'user' }, loader: async () => import('./components/Cards/User/UserProfileCard/UserProfileCard').then( m => diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index d6f2c2c360..0c177f31a8 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -31,32 +31,41 @@ import { catalogIndexRouteRef } from '../../../routes'; import { useGetEntities } from './useGetEntities'; import { EntityRelationAggregation } from '../types'; -const useStyles = makeStyles(theme => - createStyles({ - card: { - border: `1px solid ${theme.palette.divider}`, - boxShadow: theme.shadows[2], - borderRadius: '4px', - padding: theme.spacing(2), - transition: `${theme.transitions.duration.standard}ms`, - '&:hover': { - boxShadow: theme.shadows[4], +/** @public */ +export type ComponentsGridClassKey = + | 'card' + | 'bold' + | 'smallFont' + | 'entityTypeBox'; + +const useStyles = makeStyles( + theme => + createStyles({ + card: { + border: `1px solid ${theme.palette.divider}`, + boxShadow: theme.shadows[2], + borderRadius: '4px', + padding: theme.spacing(2), + transition: `${theme.transitions.duration.standard}ms`, + '&:hover': { + boxShadow: theme.shadows[4], + }, + height: '100%', }, - height: '100%', - }, - bold: { - fontWeight: theme.typography.fontWeightBold, - }, - smallFont: { - fontSize: theme.typography.body2.fontSize, - }, - entityTypeBox: { - background: (props: { type: string }) => - theme.getPageTheme({ themeId: props.type }).backgroundImage, - color: (props: { type: string }) => - theme.getPageTheme({ themeId: props.type }).fontColor, - }, - }), + bold: { + fontWeight: theme.typography.fontWeightBold, + }, + smallFont: { + fontSize: theme.typography.body2.fontSize, + }, + entityTypeBox: { + background: (props: { type: string }) => + theme.getPageTheme({ themeId: props.type }).backgroundImage, + color: (props: { type: string }) => + theme.getPageTheme({ themeId: props.type }).fontColor, + }, + }), + { name: 'PluginOrgComponentsGrid' }, ); const EntityCountTile = ({ diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index f5b01e918a..6ea0f0cbc9 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -14,10 +14,6 @@ * limitations under the License. */ -import { - GetEntitiesRequest, - GetEntitiesResponse, -} from '@backstage/catalog-client'; import { Entity, GroupEntity, UserEntity } from '@backstage/catalog-model'; import { catalogApiRef, EntityProvider } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; @@ -104,18 +100,6 @@ const items = [ }, ] as Entity[]; -const getEntitiesMock = ( - request?: GetEntitiesRequest, -): Promise => { - const filterKinds = - Array.isArray(request?.filter) && Array.isArray(request?.filter[0].kind) - ? request?.filter[0].kind ?? [] - : []; // we expect the request to be like { filter: [{ kind: ['API','System'], 'relations.ownedBy': [group:default/my-team], .... }]. If changed in OwnerShipCard, let's change in also here - return Promise.resolve({ - items: items.filter(item => filterKinds.find(k => k === item.kind)), - } as GetEntitiesResponse); -}; - describe('OwnershipCard', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -157,7 +141,8 @@ describe('OwnershipCard', () => { }; it('displays entity counts', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); + const mockedGetEntities = jest.spyOn(catalogApi, 'getEntities'); const { getByText } = await renderInTestApp( @@ -172,7 +157,7 @@ describe('OwnershipCard', () => { }, ); - expect(catalogApi.getEntities).toHaveBeenCalledWith({ + expect(mockedGetEntities).toHaveBeenCalledWith({ filter: [ { kind: ['Component', 'API', 'System'], @@ -207,7 +192,7 @@ describe('OwnershipCard', () => { }); it('applies CustomFilterDefinition', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -240,7 +225,7 @@ describe('OwnershipCard', () => { }); it('links to the catalog with the group filter', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -263,7 +248,7 @@ describe('OwnershipCard', () => { }); it('links to the catalog with the user and groups filters from an user profile', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -288,7 +273,7 @@ describe('OwnershipCard', () => { describe('OwnershipCard relations', () => { it('shows relations toggle', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByTitle } = await renderInTestApp( @@ -307,7 +292,7 @@ describe('OwnershipCard', () => { }); it('hides relations toggle', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const rendered = await renderInTestApp( @@ -326,7 +311,7 @@ describe('OwnershipCard', () => { }); it('overrides relation type', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByTitle } = await renderInTestApp( @@ -345,7 +330,7 @@ describe('OwnershipCard', () => { }); it('defaults to aggregated for User entity kind', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp( @@ -364,7 +349,7 @@ describe('OwnershipCard', () => { }); it('defaults to direct for all entity kinds except User', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp( @@ -383,7 +368,7 @@ describe('OwnershipCard', () => { }); it('defaults to provided relationsType', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp( diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index ff9fd6cec8..cf34800bf4 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -22,47 +22,62 @@ import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; import ListItemText from '@material-ui/core/ListItemText'; import Switch from '@material-ui/core/Switch'; import Tooltip from '@material-ui/core/Tooltip'; -import { makeStyles } from '@material-ui/core/styles'; +import { createStyles, makeStyles } from '@material-ui/core/styles'; import { useEffect, useState } from 'react'; import { ComponentsGrid } from './ComponentsGrid'; import { EntityRelationAggregation } from '../types'; import { useTranslationRef } from '@backstage/frontend-plugin-api'; import { orgTranslationRef } from '../../../translation'; -const useStyles = makeStyles(theme => ({ - card: { - maxHeight: '100%', +/** @public */ +export type OwnershipCardClassKey = + | 'card' + | 'cardContent' + | 'list' + | 'listItemText' + | 'listItemSecondaryAction' + | 'grid'; + +const useStyles = makeStyles( + theme => + createStyles({ + card: { + maxHeight: '100%', + }, + cardContent: { + display: 'flex', + flexDirection: 'column', + overflow: 'hidden', + }, + list: { + [theme.breakpoints.down('xs')]: { + padding: `0 0 12px`, + }, + }, + listItemText: { + [theme.breakpoints.down('xs')]: { + paddingRight: 0, + paddingLeft: 0, + }, + }, + listItemSecondaryAction: { + [theme.breakpoints.down('xs')]: { + width: '100%', + top: 'auto', + right: 'auto', + position: 'relative', + transform: 'unset', + }, + }, + grid: { + overflowY: 'auto', + marginTop: 0, + }, + }), + { + name: 'PluginOrgOwnershipCard', }, - cardContent: { - display: 'flex', - flexDirection: 'column', - overflow: 'hidden', - }, - list: { - [theme.breakpoints.down('xs')]: { - padding: `0 0 12px`, - }, - }, - listItemText: { - [theme.breakpoints.down('xs')]: { - paddingRight: 0, - paddingLeft: 0, - }, - }, - listItemSecondaryAction: { - [theme.breakpoints.down('xs')]: { - width: '100%', - top: 'auto', - right: 'auto', - position: 'relative', - transform: 'unset', - }, - }, - grid: { - overflowY: 'auto', - marginTop: 0, - }, -})); +); /** @public */ export const OwnershipCard = (props: { diff --git a/plugins/org/src/components/Cards/OwnershipCard/index.ts b/plugins/org/src/components/Cards/OwnershipCard/index.ts index dc0cef0226..df92d6214e 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/index.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export * from './OwnershipCard'; +export type { ComponentsGridClassKey } from './ComponentsGrid'; diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx index fdfe3fd5c3..ba3ee9d561 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx @@ -25,7 +25,7 @@ import { InfoCardVariants, Link, } from '@backstage/core-components'; -import { makeStyles } from '@material-ui/core/styles'; +import { createStyles, makeStyles } from '@material-ui/core/styles'; import Box from '@material-ui/core/Box'; import Grid from '@material-ui/core/Grid'; import BaseButton from '@material-ui/core/ButtonBase'; @@ -58,21 +58,31 @@ import { useCallback, useState } from 'react'; import { useTranslationRef } from '@backstage/frontend-plugin-api'; import { orgTranslationRef } from '../../../../translation'; -const useStyles = makeStyles((theme: any) => ({ - closeButton: { - position: 'absolute', - right: theme.spacing(1), - top: theme.spacing(1), - color: theme.palette.grey[500], - }, - moreButton: { - display: 'contents', - color: theme.palette.primary.main, - }, - dialogPaper: { - minHeight: 400, - }, -})); +/** @public */ +export type UserProfileCardClassKey = + | 'closeButton' + | 'moreButton' + | 'dialogPaper'; + +const useStyles = makeStyles( + theme => + createStyles({ + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + color: theme.palette.grey[500], + }, + moreButton: { + display: 'contents', + color: theme.palette.primary.main, + }, + dialogPaper: { + minHeight: 400, + }, + }), + { name: 'PluginOrgUserProfileCard' }, +); const CardTitle = (props: { title?: string }) => props.title ? ( diff --git a/plugins/org/src/overridableComponents.ts b/plugins/org/src/overridableComponents.ts index 11381ff7d7..b4c5f31212 100644 --- a/plugins/org/src/overridableComponents.ts +++ b/plugins/org/src/overridableComponents.ts @@ -16,12 +16,21 @@ import { Overrides } from '@material-ui/core/styles/overrides'; import { StyleRules } from '@material-ui/core/styles/withStyles'; -import { MemberComponentClassKey, MembersListCardClassKey } from './components'; +import { + ComponentsGridClassKey, + MemberComponentClassKey, + MembersListCardClassKey, + OwnershipCardClassKey, + UserProfileCardClassKey, +} from './components'; /** @public */ export type CatalogReactComponentsNameToClassKey = { PluginOrgMemberComponent: MemberComponentClassKey; PluginOrgMembersListCardComponent: MembersListCardClassKey; + PluginOrgOwnershipCard: OwnershipCardClassKey; + PluginOrgComponentsGrid: ComponentsGridClassKey; + PluginOrgUserProfileCard: UserProfileCardClassKey; }; /** @public */ diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index ed05fc0897..42d8ae2bb6 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.2.9 ### 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 8a9a103618..ccaa929c25 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.9", + "version": "0.2.10", "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 41094f6485..32a6f99ec6 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-permission-backend +## 0.7.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.7.1 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index db494304b9..dfb99ae96e 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.1", + "version": "0.7.2", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index a8355d2dd7..d3d9d320ca 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-permission-common +## 0.9.1 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + +## 0.9.1-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + ## 0.9.0 ### Minor Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 95c1fa9a00..e12c557d4d 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-common", - "version": "0.9.0", + "version": "0.9.1", "description": "Isomorphic types and client for Backstage permissions and authorization", "backstage": { "role": "common-library", diff --git a/packages/canon/src/components/Tabs/types.ts b/plugins/permission-common/src/types/deprecated.ts similarity index 53% rename from packages/canon/src/components/Tabs/types.ts rename to plugins/permission-common/src/types/deprecated.ts index f3b6342761..e2a4e404e4 100644 --- a/packages/canon/src/components/Tabs/types.ts +++ b/plugins/permission-common/src/types/deprecated.ts @@ -13,13 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Tabs } from '@base-ui-components/react/tabs'; -// We are not supporting the orientation prop, so we need to omit it +import { EvaluatePermissionRequest, EvaluatePermissionResponse } from './api'; +import { AuthorizeRequestOptions } from './permission'; -/** @public */ -export interface TabsRootWithoutOrientation - extends Omit< - React.ComponentPropsWithoutRef, - 'orientation' - > {} +/** + * A client interacting with the permission backend can implement this authorizer interface. + * @public + * @deprecated Use {@link @backstage/plugin-permission-common#PermissionEvaluator} instead + */ +export interface PermissionAuthorizer { + authorize( + requests: EvaluatePermissionRequest[], + options?: AuthorizeRequestOptions, + ): Promise; +} diff --git a/plugins/permission-common/src/types/index.ts b/plugins/permission-common/src/types/index.ts index f5380541df..60a588ffd2 100644 --- a/plugins/permission-common/src/types/index.ts +++ b/plugins/permission-common/src/types/index.ts @@ -48,8 +48,8 @@ export type { BasicPermission, PermissionAttributes, Permission, - PermissionAuthorizer, PermissionBase, ResourcePermission, AuthorizeRequestOptions, } from './permission'; +export type { PermissionAuthorizer } from './deprecated'; diff --git a/plugins/permission-common/src/types/permission.ts b/plugins/permission-common/src/types/permission.ts index eb1c0eb50d..69a0b0ebbd 100644 --- a/plugins/permission-common/src/types/permission.ts +++ b/plugins/permission-common/src/types/permission.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { EvaluatePermissionRequest, EvaluatePermissionResponse } from './api'; - /** * The attributes related to a given permission; these should be generic and widely applicable to * all permissions in the system. @@ -88,18 +86,6 @@ export type ResourcePermission = } >; -/** - * A client interacting with the permission backend can implement this authorizer interface. - * @public - * @deprecated Use {@link @backstage/plugin-permission-common#PermissionEvaluator} instead - */ -export interface PermissionAuthorizer { - authorize( - requests: EvaluatePermissionRequest[], - options?: AuthorizeRequestOptions, - ): Promise; -} - /** * Options for authorization requests. * @public diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 76ac7984e0..3734f3e7da 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-permission-node +## 0.10.2 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + +## 0.10.2-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + ## 0.10.1 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 65c81820ec..c26cb43ac8 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.1", + "version": "0.10.2", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-node/src/index.ts b/plugins/permission-node/src/index.ts index 32d71ddeb3..ab97b57021 100644 --- a/plugins/permission-node/src/index.ts +++ b/plugins/permission-node/src/index.ts @@ -21,5 +21,5 @@ */ export * from './integration'; export * from './policy'; -export * from './types'; +export type { PermissionRule, PermissionRuleset } from './types'; export { ServerPermissionClient } from './ServerPermissionClient'; diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 4ee937866b..522e60bac5 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -30,9 +30,8 @@ import { PermissionCriteria, PolicyDecision, } from '@backstage/plugin-permission-common'; -import { PermissionRule, PermissionRuleset } from '../types'; +import { NoInfer, PermissionRule, PermissionRuleset } from '../types'; import { - NoInfer, createGetRule, isAndCriteria, isNotCriteria, diff --git a/plugins/permission-node/src/integration/createPermissionRule.ts b/plugins/permission-node/src/integration/createPermissionRule.ts index ba6f41145b..36f8205cf8 100644 --- a/plugins/permission-node/src/integration/createPermissionRule.ts +++ b/plugins/permission-node/src/integration/createPermissionRule.ts @@ -18,10 +18,9 @@ import { PermissionCriteria, PermissionRuleParams, } from '@backstage/plugin-permission-common'; -import { PermissionRule } from '../types'; +import { NoInfer, PermissionRule } from '../types'; import { z } from 'zod'; import { PermissionResourceRef } from './createPermissionResourceRef'; -import { NoInfer } from './util'; /** * @public diff --git a/plugins/permission-node/src/integration/util.ts b/plugins/permission-node/src/integration/util.ts index 9be90e15fc..c2fa200237 100644 --- a/plugins/permission-node/src/integration/util.ts +++ b/plugins/permission-node/src/integration/util.ts @@ -22,14 +22,6 @@ import { } from '@backstage/plugin-permission-common'; import { PermissionRule } from '../types'; -/** - * Prevent use of type parameter from contributing to type inference. - * - * https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795 - * @ignore - */ -export type NoInfer = T extends infer S ? S : never; - /** * Utility function used to parse a PermissionCriteria * @param criteria - a PermissionCriteria diff --git a/plugins/permission-node/src/types.ts b/plugins/permission-node/src/types.ts index b1585d1827..578117a4f1 100644 --- a/plugins/permission-node/src/types.ts +++ b/plugins/permission-node/src/types.ts @@ -19,7 +19,15 @@ import type { PermissionRuleParams, } from '@backstage/plugin-permission-common'; import { z } from 'zod'; -import { NoInfer } from './integration/util'; + +/** + * Prevent use of type parameter from contributing to type inference. + * + * https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795 + * + * @ignore + */ +export type NoInfer = T extends infer S ? S : never; /** * A conditional rule that can be provided in an diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 8d591c0bdb..df0bc44dc3 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-permission-react +## 0.4.36 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/core-plugin-api@1.10.9 + +## 0.4.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/core-plugin-api@1.10.9-next.0 + ## 0.4.35 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 062bd8bc47..6e15c5fdeb 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.35", + "version": "0.4.36", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index d619d13779..ea92267117 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-proxy-backend +## 0.6.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-proxy-node@0.1.6 + +## 0.6.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-proxy-node@0.1.6-next.0 + ## 0.6.3 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index e925722ca3..afca7ffcef 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.3", + "version": "0.6.4", "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 b06ed5f44e..2832488656 100644 --- a/plugins/proxy-node/CHANGELOG.md +++ b/plugins/proxy-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-proxy-node +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/proxy-node/package.json b/plugins/proxy-node/package.json index 0d2d372fdd..df02f42e07 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.5", + "version": "0.1.6", "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 8df6679a1d..821c75e583 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 865262795b..159fce760b 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.10", + "version": "0.2.11", "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 d301f3c62c..3256e16f89 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.1-next.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index d3244cb55b..fc3c0857d2 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.10", + "version": "0.2.11", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index e65f866b2a..c98ec6a80a 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index 10cd7ddd3d..b75255a92b 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.10", + "version": "0.2.11", "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 24566d2810..db86d94449 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11 + +## 0.3.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.2 + +## 0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.1 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.3.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 09b4b4a14f..2819fec827 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.11", + "version": "0.3.12", "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 41fdbd8e44..e6461a008b 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.11 + +### Patch Changes + +- 642282d: Added support for new link format for on-prem Confluence +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.3.11-next.2 + +### Patch Changes + +- 642282d: Added support for new link format for on-prem Confluence +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.3.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/README.md b/plugins/scaffolder-backend-module-confluence-to-markdown/README.md index d3722f1227..7ea832b80b 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/README.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/README.md @@ -106,7 +106,7 @@ spec: properties: confluenceUrls: type: array - description: Urls for Confluence doc to be converted to markdown. In format /display// or /spaces//pages// for Confluence cloud + description: Urls for Confluence doc to be converted to markdown. In format /display// or /spaces//pages// items: type: string ui:options: diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index f3d1cead73..5a705f2e7c 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.10", + "version": "0.3.11", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.test.ts index 42d83c18a8..9acf40d6c2 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.test.ts @@ -50,6 +50,17 @@ describe('createConfluenceVariables', () => { expect(title).toEqual('Cloud+Page+Title'); expect(titleWithSpaces).toEqual('Cloud Page Title'); }); + + it('should return values for Confluence Url using spaces (non-cloud)', () => { + const url = + 'https://confluence.example.com/spaces/SPACEKEY/pages/1234567/Confluence+Page+Title'; + + const { spacekey, title, titleWithSpaces } = createConfluenceVariables(url); + + expect(spacekey).toEqual('SPACEKEY'); + expect(title).toEqual('Confluence+Page+Title'); + expect(titleWithSpaces).toEqual('Confluence Page Title'); + }); }); describe('getConfluenceConfig', () => { diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts index bbc722b1d5..04d475677c 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts @@ -15,7 +15,7 @@ */ import { Config } from '@backstage/config'; -import { ResponseError, ConflictError, InputError } from '@backstage/errors'; +import { ResponseError, ConflictError } from '@backstage/errors'; import fs from 'fs-extra'; import { Readable } from 'stream'; @@ -188,26 +188,24 @@ export const createConfluenceVariables = (url: string) => { let title: string | undefined = undefined; let titleWithSpaces: string | undefined = ''; const params = new URL(url); - if (params.pathname.split('/')[1] === 'display') { - // https://confluence.example.com/display/SPACEKEY/Page+Title - spacekey = params.pathname.split('/')[2]; - title = params.pathname.split('/')[3]; - titleWithSpaces = title?.replace(/\+/g, ' '); - return { spacekey, title, titleWithSpaces }; - } else if (params.pathname.split('/')[2] === 'display') { - // https://confluence.example.com/prefix/display/SPACEKEY/Page+Title - spacekey = params.pathname.split('/')[3]; - title = params.pathname.split('/')[4]; - titleWithSpaces = title?.replace(/\+/g, ' '); - return { spacekey, title, titleWithSpaces }; - } else if (params.pathname.split('/')[2] === 'spaces') { - // https://example.atlassian.net/wiki/spaces/SPACEKEY/pages/1234567/Page+Title - spacekey = params.pathname.split('/')[3]; - title = params.pathname.split('/')[6]; - titleWithSpaces = title?.replace(/\+/g, ' '); - return { spacekey, title, titleWithSpaces }; + const pathParts = params.pathname.split('/').filter(Boolean); + + if (pathParts.includes('display')) { + // /display// + const idx = pathParts.indexOf('display'); + spacekey = pathParts[idx + 1]; + title = pathParts[idx + 2]; + } else if (pathParts.includes('spaces')) { + // /spaces/<SPACEKEY>/pages/<PAGEID>/<TITLE> + const idx = pathParts.indexOf('spaces'); + spacekey = pathParts[idx + 1]; + title = pathParts[pathParts.length - 1]; + } else { + throw new Error( + 'The Url format for Confluence is incorrect. Acceptable format is `<CONFLUENCE_BASE_URL>/display/<SPACEKEY>/<PAGE+TITLE>` or `<CONFLUENCE_BASE_URL>/spaces/<SPACEKEY>/pages/<PAGEID>/<PAGE+TITLE>`', + ); } - throw new InputError( - 'The Url format for Confluence is incorrect. Acceptable format is `<CONFLUENCE_BASE_URL>/display/<SPACEKEY>/<PAGE+TITLE>` or `<CONFLUENCE_BASE_URL>/spaces/<SPACEKEY>/pages/<PAGEID>/<PAGE+TITLE>` for Confluence cloud', - ); + + titleWithSpaces = title?.replace(/\+/g, ' '); + return { spacekey, title, titleWithSpaces }; }; diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index a3bea154d8..06de03298d 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.13 + +### Patch Changes + +- cf9ba6f: Fixing the typescript issue with using `z.unknown()` +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-defaults@0.11.1 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.3.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.3.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.3.13-next.0 + +### Patch Changes + +- cf9ba6f: Fixing the typescript issue with using `z.unknown()` +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.3.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index aa07d95a8f..0214a338b1 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.11", + "version": "0.3.13", "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 8f6d77f907..45a9ef9523 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 5c3ee5dc13..41a446dbe0 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.10", + "version": "0.2.11", "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 d795bf2275..fafea51f68 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index be5b4103fe..be98b47145 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.10", + "version": "0.2.11", "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 e4cf277e46..a7e59c6720 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 3218a3f649..7e6893fae6 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.10", + "version": "0.2.11", "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 88220d2042..7b028f4023 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.8.1 + +### Patch Changes + +- f36bcf9: Added support for file deletion to `publish:github:pull-request` action. + + Example usage: + + ```diff + - action: publish:github:pull-request + id: clean-up-pr + input: + description: This is the description + + filesToDelete: + + - outdated/changelog.md + + - sample-file.txt + owner: owner + repo: repo + title: Title Goes Here + + ``` + +- 38db3eb: Fix typo in `InputError` +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-node@1.17.2 + +## 0.8.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.8.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 0.8.1-next.0 + +### Patch Changes + +- f36bcf9: Added support for file deletion to `publish:github:pull-request` action. + + Example usage: + + ```diff + - action: publish:github:pull-request + id: clean-up-pr + input: + description: This is the description + + filesToDelete: + + - outdated/changelog.md + + - sample-file.txt + owner: owner + repo: repo + title: Title Goes Here + + ``` + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.8.0 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 3e074432d2..6160012ba1 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.8.0", + "version": "0.8.1", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/report.api.md b/plugins/scaffolder-backend-module-github/report.api.md index 28f710557a..2941be7702 100644 --- a/plugins/scaffolder-backend-module-github/report.api.md +++ b/plugins/scaffolder-backend-module-github/report.api.md @@ -446,6 +446,7 @@ export const createPublishGithubPullRequestAction: ( branchName: string; title: string; description: string; + filesToDelete?: string[] | undefined; targetBranchName?: string | undefined; draft?: boolean | undefined; sourcePath?: string | undefined; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts index 670af15595..5a8019579b 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts @@ -24,9 +24,11 @@ import { TemplateAction, } from '@backstage/plugin-scaffolder-node'; import fs from 'fs-extra'; +import path from 'node:path'; import { createPublishGithubPullRequestAction } from './githubPullRequest'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { DELETE_FILE } from 'octokit-plugin-create-pull-request'; type GithubPullRequestActionInput = ReturnType< typeof createPublishGithubPullRequestAction @@ -50,8 +52,6 @@ describe('createPublishGithubPullRequestAction', () => { const workspacePath = mockDir.resolve('workspace'); beforeEach(() => { - mockDir.clear(); - config = new ConfigReader({}); integrations = ScmIntegrations.fromConfig(config); fakeClient = { @@ -92,6 +92,7 @@ describe('createPublishGithubPullRequestAction', () => { }); afterEach(() => { + mockDir.clear(); jest.resetAllMocks(); }); @@ -304,6 +305,118 @@ describe('createPublishGithubPullRequestAction', () => { }); }); + describe('with filesToDelete', () => { + let input: GithubPullRequestActionInput; + let ctx: ActionContext<GithubPullRequestActionInput, any, any>; + + beforeEach(() => { + input = { + filesToDelete: ['changed-file-to-delete.txt', 'delete-me-too.md'], + repoUrl: 'github.com?owner=myorg&repo=myrepo', + title: 'Create my new app', + branchName: 'new-app', + description: 'This PR is really good', + }; + + mockDir.setContent({ + [workspacePath]: { + 'catpants.md': 'cat + pants', + 'changed-file-to-delete.txt': 'file is changed and deleted', + 'foobar.txt': 'Hello there!', + }, + }); + + ctx = createMockActionContext({ input, workspacePath }); + }); + + it('should delete named files', async () => { + await instance.handler(ctx); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'myorg', + repo: 'myrepo', + title: input.title, + head: input.branchName, + body: input.description, + changes: [ + { + commit: input.title, + files: { + 'catpants.md': { + content: Buffer.from('cat + pants').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + 'foobar.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + 'changed-file-to-delete.txt': DELETE_FILE, + 'delete-me-too.md': DELETE_FILE, + }, + }, + ], + }); + }); + + describe('with targetPath', () => { + const targetPath = `target-path-${Date.now()}`; + + beforeEach(() => { + Object.assign(input, { + filesToDelete: [ + path.posix.join('nested', 'catpants.md'), + path.posix.join('nested', 'delete-me.too'), + ], + targetPath, + }); + + mockDir.setContent({ + [workspacePath]: { + 'catpants.md': 'cat + pants', + 'foobar.txt': 'Hello there!', + [path.posix.join('nested', 'catpants.md')]: 'delete me', + [path.posix.join('nested', 'delete-me.too')]: 'delete me too', + }, + }); + }); + + it('should delete named files', async () => { + await instance.handler(ctx); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'myorg', + repo: 'myrepo', + title: input.title, + head: input.branchName, + body: input.description, + changes: [ + { + commit: input.title, + files: { + [path.posix.join(targetPath, 'catpants.md')]: { + content: Buffer.from('cat + pants').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + [path.posix.join(targetPath, 'foobar.txt')]: { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + [path.posix.join(targetPath, 'nested', 'catpants.md')]: + DELETE_FILE, + [path.posix.join(targetPath, 'nested', 'delete-me.too')]: + DELETE_FILE, + }, + }, + ], + }); + }); + }); + }); + describe('with repoUrl', () => { let input: GithubPullRequestActionInput; let ctx: ActionContext<GithubPullRequestActionInput, any, any>; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts index 54b90e3544..7d1e88d0c7 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts @@ -27,7 +27,10 @@ import { } from '@backstage/plugin-scaffolder-node'; import { Octokit } from 'octokit'; import { CustomErrorBase, InputError } from '@backstage/errors'; -import { createPullRequest } from 'octokit-plugin-create-pull-request'; +import { + createPullRequest, + DELETE_FILE, +} from 'octokit-plugin-create-pull-request'; import { getOctokitOptions } from '../util'; import { examples } from './githubPullRequest.examples'; import { @@ -143,6 +146,12 @@ export const createPublishGithubPullRequestAction = ( z.string({ description: 'The name for the branch', }), + filesToDelete: z => + z + .array(z.string(), { + description: 'List of files that will be deleted', + }) + .optional(), targetBranchName: z => z .string({ @@ -269,6 +278,7 @@ export const createPublishGithubPullRequestAction = ( const { repoUrl, branchName, + filesToDelete, targetBranchName, title, description, @@ -323,8 +333,8 @@ export const createPublishGithubPullRequestAction = ( file: SerializedFile, ): 'utf-8' | 'base64' => (file.symlink ? 'utf-8' : 'base64'); - const files = Object.fromEntries( - directoryContents.map(file => [ + const files = Object.fromEntries([ + ...directoryContents.map(file => [ targetPath ? path.posix.join(targetPath, file.path) : file.path, { // See the properties of tree items @@ -341,7 +351,13 @@ export const createPublishGithubPullRequestAction = ( content: file.content.toString(determineFileEncoding(file)), }, ]), - ); + // order of arrays is important so filesToDelete will overwrite + // changes from files above + ...(filesToDelete || []).map(filePath => [ + targetPath ? path.posix.join(targetPath, filePath) : filePath, + DELETE_FILE, + ]), + ]); // If this is a dry run, log and return if (ctx.isDryRun) { diff --git a/plugins/scaffolder-backend-module-github/src/util.ts b/plugins/scaffolder-backend-module-github/src/util.ts index c25ca99f5f..260c93993f 100644 --- a/plugins/scaffolder-backend-module-github/src/util.ts +++ b/plugins/scaffolder-backend-module-github/src/util.ts @@ -89,7 +89,7 @@ export async function getOctokitOptions(options: { if (!owner || !repo) { throw new InputError( - `No owner and/or owner provided, which is required if a token is not provided`, + `No owner and/or repo provided, which is required if a token is not provided`, ); } diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 16a5cf8c44..5129836fa1 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.9.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.9.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 9c0f754a03..9d0f037aa2 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.9.2", + "version": "0.9.3", "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 0cc9672729..f531a2a082 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-notifications-node@0.2.17 + +## 0.1.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-notifications-common@0.0.10-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + - @backstage/plugin-notifications-node@0.2.17-next.0 + +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/plugin-notifications-common@0.0.9 + ## 0.1.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 2f355e338e..a10cea8f51 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.11", + "version": "0.1.12", "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 6f8631be4a..6ace3a731d 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + +## 0.5.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.5.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.5.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.5.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 2afa72c360..eb3eaa272a 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.10", + "version": "0.5.11", "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 59a7223fb7..ef45ef2364 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.2.11 + +### Patch Changes + +- 648b3d7: Add optional input to sentry:project:create to set the new Sentry project's platform +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/backend-plugin-api@1.4.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 260b9f4fd3..54b631124d 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.10", + "version": "0.2.11", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-sentry/report.api.md b/plugins/scaffolder-backend-module-sentry/report.api.md index 8c716b3ab3..98b3c8b599 100644 --- a/plugins/scaffolder-backend-module-sentry/report.api.md +++ b/plugins/scaffolder-backend-module-sentry/report.api.md @@ -16,6 +16,7 @@ export function createSentryCreateProjectAction(options: { teamSlug: string; name: string; slug?: string | undefined; + platform?: string | undefined; authToken?: string | undefined; }, { diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts index 3e31aef3bc..6fab15f59f 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts @@ -43,6 +43,7 @@ describe('sentry:project:create action', () => { teamSlug: string; name: string; slug?: string; + platform?: string; authToken?: string; }> => createMockActionContext({ @@ -56,12 +57,14 @@ describe('sentry:project:create action', () => { }, }); - it(`should ${examples[0].description}`, async () => { + it(`should ${examples[0].description} ${ + yaml.parse(examples[0].example).steps[2].name + }`, async () => { expect.assertions(3); let input; try { - input = yaml.parse(examples[0].example).steps[1].input; + input = yaml.parse(examples[0].example).steps[2].input; } catch (error) { console.error('Failed to parse YAML:', error); } @@ -97,7 +100,9 @@ describe('sentry:project:create action', () => { }); }); - it(`should ${examples[0].description}`, async () => { + it(`should ${examples[0].description} ${ + yaml.parse(examples[0].example).steps[0].name + }`, async () => { expect.assertions(3); let input; @@ -140,6 +145,51 @@ describe('sentry:project:create action', () => { }); }); + it(`should ${examples[0].description} ${ + yaml.parse(examples[0].example).steps[1].name + }`, async () => { + expect.assertions(3); + + let input; + try { + input = yaml.parse(examples[0].example).steps[1].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + actionContext.input = { ...actionContext.input, platform: 'platform-a' }; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${input.organizationSlug}/${input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer c25711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d5de85`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: 'Scaffolded project A', + platform: 'platform-a', + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler({ + ...actionContext, + input: { + ...actionContext.input, + ...input, + }, + }); + }); + it(`should ${examples[1].description}`, async () => { expect.assertions(3); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts index 3af88a4663..1744a995a9 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts @@ -38,7 +38,20 @@ export const examples: TemplateExample[] = [ { id: 'create-sentry-project', action: 'sentry:project:create', - name: 'Create a Sentry project without providing a project slug.', + name: 'Create a Sentry project with provided platform.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-a', + name: 'Scaffolded project A', + platform: 'platform-a', + authToken: + 'c25711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d5de85', + }, + }, + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project without optional parameters.', input: { organizationSlug: 'my-org', teamSlug: 'team-b', diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index 48c437d2a4..0279c198a9 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -42,6 +42,7 @@ describe('sentry:project:create action', () => { teamSlug: string; name: string; slug?: string; + platform?: string; authToken?: string; }> => createMockActionContext({ @@ -113,6 +114,37 @@ describe('sentry:project:create action', () => { await action.handler(actionContext); }); + it('should request sentry project create with added optional specified platform', async () => { + expect.assertions(3); + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + actionContext.input = { ...actionContext.input, platform: 'platform-slug' }; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: actionContext.input.name, + slug: actionContext.input.slug, + platform: actionContext.input.platform, + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler(actionContext); + }); + it('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { expect.assertions(3); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 226c31bd05..57f8b349e0 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -54,6 +54,12 @@ export function createSentryCreateProjectAction(options: { config: Config }) { 'Optional slug for the new project. If not provided a slug is generated from the name', }) .optional(), + platform: z => + z + .string({ + description: 'Optional sentry platform for the new project. ', + }) + .optional(), authToken: z => z .string({ @@ -64,7 +70,8 @@ export function createSentryCreateProjectAction(options: { config: Config }) { }, }, async handler(ctx) { - const { organizationSlug, teamSlug, name, slug, authToken } = ctx.input; + const { organizationSlug, teamSlug, name, slug, platform, authToken } = + ctx.input; const body: any = { name: name, @@ -74,6 +81,10 @@ export function createSentryCreateProjectAction(options: { config: Config }) { body.slug = slug; } + if (platform) { + body.platform = platform; + } + const token = authToken ? authToken : config.getOptionalString('scaffolder.sentry.token'); diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 599c5f73d9..f4742d65f5 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.1 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/backend-plugin-api@1.4.1 + +## 0.4.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + - @backstage/plugin-scaffolder-node-test-utils@0.3.1-next.2 + +## 0.4.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.3.1-next.1 + +## 0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + ## 0.4.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index c8199d0c3a..0165cc033d 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.11", + "version": "0.4.12", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 2169f7d96c..10d0a43a0c 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,128 @@ # @backstage/plugin-scaffolder-backend +## 2.1.0 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- 424610a: Scaffolder audit Log now includes taskId and createdBy +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- fc70b43: Replaced deprecated uses of `@backstage/backend-common` with the equivalents in `@backstage/backend-defaults` and `@backstage/backend-plugin-api`. +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-defaults@0.11.1 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/integration@1.17.1 + - @backstage/plugin-scaffolder-backend-module-github@0.8.1 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.10 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-events-node@0.4.13 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.11 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3 + +## 2.1.0-next.2 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.10-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.8.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3-next.2 + +## 2.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3-next.1 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.10-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + +## 2.0.1-next.0 + +### Patch Changes + +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- fc70b43: Replaced deprecated uses of `@backstage/backend-common` with the equivalents in `@backstage/backend-defaults` and `@backstage/backend-plugin-api`. +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.8.1-next.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.11-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 2.0.0 ### Major Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 91e669c4f5..6cef18efce 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "2.0.0", + "version": "2.1.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend/report-alpha.api.md b/plugins/scaffolder-backend/report-alpha.api.md index 958d68fc25..966d71acaa 100644 --- a/plugins/scaffolder-backend/report-alpha.api.md +++ b/plugins/scaffolder-backend/report-alpha.api.md @@ -10,6 +10,8 @@ import { PermissionCondition } from '@backstage/plugin-permission-common'; import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { ResourcePermission } from '@backstage/plugin-permission-common'; +import { SerializedTask } from '@backstage/plugin-scaffolder-node'; +import { TaskFilter } from '@backstage/plugin-scaffolder-node'; import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; @@ -19,6 +21,12 @@ export const createScaffolderActionConditionalDecision: ( conditions: PermissionCriteria<PermissionCondition<'scaffolder-action'>>, ) => ConditionalPolicyDecision; +// @alpha (undocumented) +export const createScaffolderTaskConditionalDecision: ( + permission: ResourcePermission<'scaffolder-task'>, + conditions: PermissionCriteria<PermissionCondition<'scaffolder-task'>>, +) => ConditionalPolicyDecision; + // @alpha export const createScaffolderTemplateConditionalDecision: ( permission: ResourcePermission<'scaffolder-template'>, @@ -76,6 +84,18 @@ export const scaffolderActionConditions: Conditions<{ >; }>; +// @alpha +export const scaffolderTaskConditions: Conditions<{ + isTaskOwner: PermissionRule< + SerializedTask, + TaskFilter, + 'scaffolder-task', + { + createdBy: string[]; + } + >; +}>; + // @alpha export const scaffolderTemplateConditions: Conditions<{ hasTag: PermissionRule< diff --git a/plugins/scaffolder-backend/report.api.md b/plugins/scaffolder-backend/report.api.md index 7ece0f84ea..ada936c6e9 100644 --- a/plugins/scaffolder-backend/report.api.md +++ b/plugins/scaffolder-backend/report.api.md @@ -16,6 +16,7 @@ import { HumanDuration } from '@backstage/types'; import { JsonObject } from '@backstage/types'; import { Knex } from 'knex'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; @@ -27,6 +28,7 @@ import { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node'; import { TaskBroker } from '@backstage/plugin-scaffolder-node'; import { TaskCompletionState } from '@backstage/plugin-scaffolder-node'; import { TaskContext } from '@backstage/plugin-scaffolder-node'; +import { TaskFilters } from '@backstage/plugin-scaffolder-node'; import { TaskRecovery } from '@backstage/plugin-scaffolder-common'; import { TaskSecrets } from '@backstage/plugin-scaffolder-node'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; @@ -351,6 +353,7 @@ export class DatabaseTaskStore implements TaskStore { order: 'asc' | 'desc'; field: string; }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number; @@ -442,6 +445,8 @@ export class TaskManager implements TaskContext { // (undocumented) get spec(): TaskSpecV1beta3; // (undocumented) + get taskId(): string; + // (undocumented) updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>; } @@ -486,6 +491,7 @@ export interface TaskStore { limit?: number; offset?: number; }; + permissionFilters?: PermissionCriteria<TaskFilters>; order?: { order: 'asc' | 'desc'; field: string; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts index f95381e0ed..03a85ad971 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts @@ -25,6 +25,8 @@ import { } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { EventsService } from '@backstage/plugin-events-node'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; +import { TaskFilters } from '@backstage/plugin-scaffolder-node'; const createStore = async (events?: EventsService) => { const manager = DatabaseManager.fromConfig( @@ -237,6 +239,56 @@ describe('DatabaseTaskStore', () => { expect(tasks[0].id).toBeDefined(); }); + it('should filter tasks based on permissionFilters', async () => { + const { store } = await createStore(); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'user:default/one', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'user:default/two', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'user:default/three', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'user:default/one', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'user:default/four', + }); + + const permissionFilters: PermissionCriteria<TaskFilters> = { + not: { + key: 'created_by', + values: ['user:default/three', 'user:default/four'], + }, + }; + + const { tasks, totalTasks } = await store.list({ + permissionFilters: permissionFilters, + }); + + expect(totalTasks).toBe(3); + + const createdByList = tasks.map(task => task.createdBy); + expect(createdByList).toEqual( + expect.arrayContaining(['user:default/one', 'user:default/two']), + ); + expect(createdByList).not.toEqual( + expect.arrayContaining(['user:default/three', 'user:default/four']), + ); + }); + it('should sent an event to start cancelling the task', async () => { const { store } = await createStore(eventsService); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index f81a79a5a0..f07d827f45 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -35,6 +35,7 @@ import { SerializedTask, SerializedTaskEvent, TaskEventType, + TaskFilter, TaskSecrets, TaskStatus, } from '@backstage/plugin-scaffolder-node'; @@ -48,6 +49,14 @@ import { } from '@backstage/plugin-scaffolder-node/alpha'; import { flattenParams } from '../../service/helpers'; import { EventsService } from '@backstage/plugin-events-node'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; +import { + isAndCriteria, + isNotCriteria, + isOrCriteria, +} from '@backstage/plugin-permission-node'; +import { TaskFilters } from '@backstage/plugin-scaffolder-node'; +import { compact } from 'lodash'; const migrationsDir = resolvePackagePath( '@backstage/plugin-scaffolder-backend', @@ -195,6 +204,48 @@ export class DatabaseTaskStore implements TaskStore { } } + private isTaskFilter(filter: any): filter is TaskFilter { + return filter.hasOwnProperty('key'); + } + + private parseFilter( + filter: PermissionCriteria<TaskFilters>, + query: Knex.QueryBuilder, + db: Knex, + negate: boolean = false, + ): Knex.QueryBuilder { + if (isNotCriteria(filter)) { + return this.parseFilter(filter.not, query, db, !negate); + } + + if (this.isTaskFilter(filter)) { + const values: string[] = compact(filter.values) ?? []; + if (negate) { + query.whereNotIn(filter.key, values); + } else { + query.whereIn(filter.key, values); + } + + return query; + } + + return query[negate ? 'andWhereNot' : 'andWhere'](subQuery => { + if (isOrCriteria(filter)) { + for (const subFilter of filter.anyOf ?? []) { + subQuery.orWhere(subQueryInner => + this.parseFilter(subFilter, subQueryInner, db, false), + ); + } + } else if (isAndCriteria(filter)) { + for (const subFilter of filter.allOf ?? []) { + subQuery.andWhere(subQueryInner => + this.parseFilter(subFilter, subQueryInner, db, false), + ); + } + } + }); + } + async list(options: { createdBy?: string; status?: TaskStatus; @@ -207,16 +258,31 @@ export class DatabaseTaskStore implements TaskStore { offset?: number; }; order?: { order: 'asc' | 'desc'; field: string }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> { - const { createdBy, status, pagination, order, filters } = options ?? {}; + const { createdBy, status, pagination, order, filters, permissionFilters } = + options ?? {}; const queryBuilder = this.db<RawDbTaskRow & { count: number }>('tasks'); - if (createdBy || filters?.createdBy) { - const arr: string[] = flattenParams<string>( - createdBy, - filters?.createdBy, - ); - queryBuilder.whereIn('created_by', [...new Set(arr)]); + const createdByValues = flattenParams<string>( + createdBy, + filters?.createdBy, + ); + + const combinedPermissionFilters: + | PermissionCriteria<TaskFilters> + | undefined = + createdByValues.length > 0 + ? { + allOf: [ + { key: 'created_by', values: createdByValues }, + ...(permissionFilters ? [permissionFilters] : []), + ], + } + : permissionFilters; + + if (combinedPermissionFilters) { + this.parseFilter(combinedPermissionFilters, queryBuilder, this.db); } if (status || filters?.status) { @@ -271,24 +337,29 @@ export class DatabaseTaskStore implements TaskStore { throw new NotFoundError(`No task with id '${taskId}' found`); } try { - const spec = JSON.parse(result.spec); - const secrets = result.secrets ? JSON.parse(result.secrets) : undefined; - const state = this.getState(result); - return { - id: result.id, - spec, - status: result.status, - lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at), - createdAt: parseSqlDateToIsoString(result.created_at), - createdBy: result.created_by ?? undefined, - secrets, - state, - }; + return this.parseTaskRow(result); } catch (error) { throw new Error(`Failed to parse spec of task '${taskId}', ${error}`); } } + private parseTaskRow(result: RawDbTaskRow): SerializedTask { + const spec = JSON.parse(result.spec); + const secrets = result.secrets ? JSON.parse(result.secrets) : undefined; + const state = this.getState(result); + + return { + id: result.id, + spec, + status: result.status, + lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at), + createdAt: parseSqlDateToIsoString(result.created_at), + createdBy: result.created_by ?? undefined, + secrets, + state, + }; + } + async createTask( options: TaskStoreCreateTaskOptions, ): Promise<TaskStoreCreateTaskResult> { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index c88a1f687c..5b4d568144 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -29,6 +29,7 @@ import { TaskBrokerDispatchOptions, TaskCompletionState, TaskContext, + TaskFilters, TaskSecrets, TaskStatus, } from '@backstage/plugin-scaffolder-node'; @@ -42,6 +43,7 @@ import ObservableImpl from 'zen-observable'; import { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService'; import { readDuration } from './helper'; import { InternalTaskSecrets, TaskStore } from './types'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; type TaskState = { checkpoints: CheckpointState; @@ -94,6 +96,10 @@ export class TaskManager implements TaskContext { private readonly auth?: AuthService, ) {} + get taskId() { + return this.task.taskId; + } + get spec() { return this.task.spec; } @@ -269,6 +275,7 @@ export class StorageTaskBroker implements TaskBroker { offset?: number; }; order?: { order: 'asc' | 'desc'; field: string }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> { if (!this.storage.list) { throw new Error( diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index b0c3166ff6..24871ca452 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -189,6 +189,7 @@ export class TaskWorker { meta: { actionType: 'execution', taskId: task.taskId, + createdBy: task.createdBy, taskParameters: task.spec.parameters, templateRef: task.spec.templateInfo?.entityRef, }, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index a3d9e3b741..62ffb171ff 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -23,7 +23,9 @@ import { SerializedTaskEvent, SerializedTask, TaskStatus, + TaskFilters, } from '@backstage/plugin-scaffolder-node'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; /** * TaskStoreEmitOptions @@ -131,6 +133,7 @@ export interface TaskStore { limit?: number; offset?: number; }; + permissionFilters?: PermissionCriteria<TaskFilters>; order?: { order: 'asc' | 'desc'; field: string }[]; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }>; diff --git a/plugins/scaffolder-backend/src/service/alpha.ts b/plugins/scaffolder-backend/src/service/alpha.ts index 7d22c9d262..ac14f0b1ba 100644 --- a/plugins/scaffolder-backend/src/service/alpha.ts +++ b/plugins/scaffolder-backend/src/service/alpha.ts @@ -17,9 +17,14 @@ import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, RESOURCE_TYPE_SCAFFOLDER_ACTION, + RESOURCE_TYPE_SCAFFOLDER_TASK, } from '@backstage/plugin-scaffolder-common/alpha'; import { createConditionExports } from '@backstage/plugin-permission-node'; -import { scaffolderTemplateRules, scaffolderActionRules } from './rules'; +import { + scaffolderTemplateRules, + scaffolderActionRules, + scaffolderTaskRules, +} from './rules'; const templateConditionExports = createConditionExports({ pluginId: 'scaffolder', @@ -33,6 +38,12 @@ const actionsConditionExports = createConditionExports({ rules: scaffolderActionRules, }); +const taskConditionExports = createConditionExports({ + pluginId: 'scaffolder', + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, + rules: scaffolderTaskRules, +}); + /** * `createScaffolderTemplateConditionalDecision` can be used when authoring policies to * create conditional decisions. It requires a permission of type @@ -90,3 +101,17 @@ export const createScaffolderActionConditionalDecision = * @alpha */ export const scaffolderActionConditions = actionsConditionExports.conditions; + +/** + * @alpha + */ +export const createScaffolderTaskConditionalDecision = + taskConditionExports.createConditionalDecision; + +/** + * These conditions are used when creating conditional decisions for scaffolder + * tasks that are returned by authorization policies. + * + * @alpha + */ +export const scaffolderTaskConditions = taskConditionExports.conditions; diff --git a/plugins/scaffolder-backend/src/service/permissions.ts b/plugins/scaffolder-backend/src/service/permissions.ts index 9b12e115b9..b73cce7a74 100644 --- a/plugins/scaffolder-backend/src/service/permissions.ts +++ b/plugins/scaffolder-backend/src/service/permissions.ts @@ -21,9 +21,20 @@ import { } from '@backstage/plugin-scaffolder-common'; import { RESOURCE_TYPE_SCAFFOLDER_ACTION, + RESOURCE_TYPE_SCAFFOLDER_TASK, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, } from '@backstage/plugin-scaffolder-common/alpha'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; +import { SerializedTask } from '@backstage/plugin-scaffolder-node'; + +/** + * + * @public + */ +export type ScaffolderPermissionRuleInput = + | TemplatePermissionRuleInput + | ActionPermissionRuleInput + | TaskPermissionRuleInput; /** * @public @@ -37,7 +48,7 @@ export type TemplatePermissionRuleInput< TParams >; export function isTemplatePermissionRuleInput( - permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput, + permissionRule: ScaffolderPermissionRuleInput, ): permissionRule is TemplatePermissionRuleInput { return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE; } @@ -55,7 +66,27 @@ export type ActionPermissionRuleInput< TParams >; export function isActionPermissionRuleInput( - permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput, + permissionRule: ScaffolderPermissionRuleInput, ): permissionRule is ActionPermissionRuleInput { return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION; } + +/** + * @public + */ +export type TaskPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule< + SerializedTask, + { + key: string; + values?: string[]; + }, + typeof RESOURCE_TYPE_SCAFFOLDER_TASK, + TParams +>; +export function isTaskPermissionRuleInput( + permissionRule: ScaffolderPermissionRuleInput, +): permissionRule is TaskPermissionRuleInput { + return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TASK; +} diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 2820c8b8dc..bebfadb9b1 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -948,6 +948,36 @@ describe('scaffolder router', () => { order: [{ order: 'desc', field: 'created_at' }], }); }); + + it('disallows users from seeing tasks they do not own', async () => { + const { router, taskBroker, permissions } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + conditions: { + resourceType: 'scaffolder-task', + rule: 'IS_TASK_OWNER', + params: { createdBy: ['user'] }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-task', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + const response = await request(router).get( + `/v2/tasks?createdBy=not-user`, + ); + expect(taskBroker.list).toHaveBeenCalledWith({ + filters: { createdBy: ['not-user'], status: undefined }, + order: undefined, + pagination: { limit: undefined, offset: undefined }, + permissionFilters: { key: 'created_by', values: ['user'] }, + }); + expect(response.status).toBe(200); + expect(response.body.totalTasks).toBe(0); + expect(response.body.tasks).toEqual([]); + }); }); describe('GET /v2/tasks/:taskId', () => { @@ -969,11 +999,52 @@ describe('scaffolder router', () => { expect(response.body.status).toBe('completed'); expect(response.body.secrets).toBeUndefined(); }); + it('disallows users from seeing tasks they do not own', async () => { + const { router, permissions, taskBroker } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + conditions: { + resourceType: 'scaffolder-task', + rule: 'IS_TASK_OWNER', + params: { createdBy: ['user'] }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-task', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: 'not-user', + }); + + const response = await request(router).get(`/v2/tasks/a-random-id`); + expect(taskBroker.get).toHaveBeenCalledWith('a-random-id'); + expect(response.error).not.toBeFalsy(); + }); }); describe('GET /v2/tasks/:taskId/eventstream', () => { it('should return log messages', async () => { const { router, taskBroker } = await createTestRouter(); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: '', + }); let subscriber: ZenObservable.SubscriptionObserver<{ events: SerializedTaskEvent[]; }>; @@ -1059,6 +1130,16 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ it('should return log messages with after query', async () => { const { router, taskBroker } = await createTestRouter(); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: '', + }); let subscriber: ZenObservable.SubscriptionObserver<{ events: SerializedTaskEvent[]; }>; @@ -1123,6 +1204,16 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ describe('GET /v2/tasks/:taskId/events', () => { it('should return log messages', async () => { const { router, taskBroker } = await createTestRouter(); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: '', + }); let subscriber: ZenObservable.SubscriptionObserver<{ events: SerializedTaskEvent[]; }>; @@ -1183,6 +1274,16 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ it('should return log messages with after query', async () => { const { router, taskBroker } = await createTestRouter(); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: '', + }); let subscriber: ZenObservable.SubscriptionObserver<{ events: SerializedTaskEvent[]; }>; @@ -1209,6 +1310,40 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ }); expect(subscriber!.closed).toBe(true); }); + it('disallows users from seeing events for tasks they do not own', async () => { + const { permissions, router, taskBroker } = await createTestRouter(); + + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + conditions: { + resourceType: 'scaffolder-task', + rule: 'IS_TASK_OWNER', + params: { createdBy: ['user'] }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-task', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + (taskBroker.get as jest.Mocked<TaskBroker>['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as any, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: 'not-user', + }); + + const response = await request(router).get( + `/v2/tasks/a-random-id/events`, + ); + expect(taskBroker.get).toHaveBeenCalledWith('a-random-id'); + expect(response.error).not.toBeFalsy(); + }); }); describe('POST /v2/dry-run', () => { @@ -1236,6 +1371,35 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect.anything(), ); }); + it('disallows users from seeing tasks they do not own', async () => { + const { permissions, router, taskBroker } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + conditions: { + resourceType: 'scaffolder-task', + rule: 'IS_TASK_OWNER', + params: { createdBy: ['user'] }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-task', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + const response = await request(router).get( + `/v2/tasks?createdBy=not-user`, + ); + expect(taskBroker.list).toHaveBeenCalledWith({ + filters: { createdBy: ['not-user'], status: undefined }, + order: undefined, + pagination: { limit: undefined, offset: undefined }, + permissionFilters: { key: 'created_by', values: ['user'] }, + }); + expect(response.status).toBe(200); + expect(response.body.totalTasks).toBe(0); + expect(response.body.tasks).toEqual([]); + }); }); describe('GET /v2/autocomplete/:provider/:resource', () => { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 0ea6293f36..6e476d9a19 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -42,6 +42,8 @@ import { EventsService } from '@backstage/plugin-events-node'; import { createConditionAuthorizer, createPermissionIntegrationRouter, + createConditionTransformer, + ConditionTransformer, } from '@backstage/plugin-permission-node'; import { TaskSpec, @@ -51,7 +53,9 @@ import { import { RESOURCE_TYPE_SCAFFOLDER_ACTION, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + RESOURCE_TYPE_SCAFFOLDER_TASK, scaffolderActionPermissions, + scaffolderTaskPermissions, scaffolderPermissions, scaffolderTemplatePermissions, taskCancelPermission, @@ -89,7 +93,11 @@ import { import { createDryRunner } from '../scaffolder/dryrun'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; -import { checkPermission } from '../util/checkPermissions'; +import { + checkPermission, + checkTaskPermission, + getAuthorizeConditions, +} from '../util/checkPermissions'; import { findTemplate, getEntityBaseUrl, @@ -97,7 +105,7 @@ import { parseNumberParam, parseStringsParam, } from './helpers'; -import { scaffolderActionRules, scaffolderTemplateRules } from './rules'; + import { convertFiltersToRecord, convertGlobalsToRecord, @@ -107,6 +115,9 @@ import { } from '../util/templating'; import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters'; import { + ScaffolderPermissionRuleInput, + TaskPermissionRuleInput, + isTaskPermissionRuleInput, ActionPermissionRuleInput, isActionPermissionRuleInput, isTemplatePermissionRuleInput, @@ -114,6 +125,14 @@ import { } from './permissions'; import { CatalogService } from '@backstage/plugin-catalog-node'; +import { + scaffolderActionRules, + scaffolderTemplateRules, + scaffolderTaskRules, +} from './rules'; + +import { TaskFilters } from '@backstage/plugin-scaffolder-node'; + /** * RouterOptions */ @@ -139,9 +158,7 @@ export interface RouterOptions { | CreatedTemplateGlobal[]; additionalWorkspaceProviders?: Record<string, WorkspaceProvider>; permissions?: PermissionsService; - permissionRules?: Array< - TemplatePermissionRuleInput | ActionPermissionRuleInput - >; + permissionRules?: Array<ScaffolderPermissionRuleInput>; auth: AuthService; httpAuth: HttpAuthService; events?: EventsService; @@ -312,15 +329,24 @@ export async function createRouter( const actionRules: ActionPermissionRuleInput[] = Object.values( scaffolderActionRules, ); + const taskRules: TaskPermissionRuleInput[] = + Object.values(scaffolderTaskRules); if (permissionRules) { templateRules.push( ...permissionRules.filter(isTemplatePermissionRuleInput), ); actionRules.push(...permissionRules.filter(isActionPermissionRuleInput)); + taskRules.push(...permissionRules.filter(isTaskPermissionRuleInput)); } - const isAuthorized = createConditionAuthorizer(Object.values(templateRules)); + const isTemplateAuthorized = createConditionAuthorizer( + Object.values(templateRules), + ); + const isTaskAuthorized = createConditionAuthorizer(Object.values(taskRules)); + + const taskTransformConditions: ConditionTransformer<TaskFilters> = + createConditionTransformer(Object.values(taskRules)); const permissionIntegrationRouter = createPermissionIntegrationRouter({ resources: [ @@ -334,6 +360,11 @@ export async function createRouter( permissions: scaffolderActionPermissions, rules: actionRules, }, + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, + permissions: scaffolderTaskPermissions, + rules: taskRules, + }, ], permissions: scaffolderPermissions, }); @@ -532,11 +563,6 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); - await checkPermission({ - credentials, - permissions: [taskReadPermission], - permissionService: permissions, - }); if (!taskBroker.list) { throw new Error( @@ -564,6 +590,13 @@ export async function createRouter( const limit = parseNumberParam(req.query.limit, 'limit'); const offset = parseNumberParam(req.query.offset, 'offset'); + const taskPermissionFilters = await getAuthorizeConditions({ + credentials: credentials, + permission: taskReadPermission, + permissionService: permissions, + transformConditions: taskTransformConditions, + }); + const tasks = await taskBroker.list({ filters: { createdBy, @@ -574,6 +607,7 @@ export async function createRouter( limit: limit ? limit[0] : undefined, offset: offset ? offset[0] : undefined, }, + permissionFilters: taskPermissionFilters, }); await auditorEvent?.success(); @@ -598,13 +632,17 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); - await checkPermission({ + + const task = await taskBroker.get(taskId); + + await checkTaskPermission({ credentials, permissions: [taskReadPermission], permissionService: permissions, + task: task, + isTaskAuthorized, }); - const task = await taskBroker.get(taskId); if (!task) { throw new NotFoundError(`Task with id ${taskId} does not exist`); } @@ -634,11 +672,14 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); + const task = await taskBroker.get(taskId); // Requires both read and cancel permissions - await checkPermission({ + await checkTaskPermission({ credentials, permissions: [taskCancelPermission, taskReadPermission], permissionService: permissions, + task: task, + isTaskAuthorized, }); await taskBroker.cancel?.(taskId); @@ -666,13 +707,23 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); - // Requires both read and cancel permissions + const task = await taskBroker.get(taskId); + + // Requires both read and create permissions await checkPermission({ credentials, - permissions: [taskCreatePermission, taskReadPermission], + permissions: [taskCreatePermission], permissionService: permissions, }); + await checkTaskPermission({ + credentials, + permissions: [taskReadPermission], + permissionService: permissions, + task: task, + isTaskAuthorized, + }); + await auditorEvent?.success(); const { token } = await auth.getPluginRequestToken({ @@ -711,10 +762,14 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); - await checkPermission({ + const task = await taskBroker.get(taskId); + + await checkTaskPermission({ credentials, permissions: [taskReadPermission], permissionService: permissions, + task: task, + isTaskAuthorized, }); const after = @@ -783,10 +838,14 @@ export async function createRouter( try { const credentials = await httpAuth.credentials(req); - await checkPermission({ + const task = await taskBroker.get(taskId); + + await checkTaskPermission({ credentials, permissions: [taskReadPermission], permissionService: permissions, + task: task, + isTaskAuthorized, }); const after = Number(req.query.after) || undefined; @@ -1023,18 +1082,18 @@ export async function createRouter( // Authorize parameters if (Array.isArray(template.spec.parameters)) { template.spec.parameters = template.spec.parameters.filter(step => - isAuthorized(parameterDecision, step), + isTemplateAuthorized(parameterDecision, step), ); } else if ( template.spec.parameters && - !isAuthorized(parameterDecision, template.spec.parameters) + !isTemplateAuthorized(parameterDecision, template.spec.parameters) ) { template.spec.parameters = undefined; } // Authorize steps template.spec.steps = template.spec.steps.filter(step => - isAuthorized(stepDecision, step), + isTemplateAuthorized(stepDecision, step), ); return template; diff --git a/plugins/scaffolder-backend/src/service/rules.test.ts b/plugins/scaffolder-backend/src/service/rules.test.ts index 8e24cacb32..85e393247a 100644 --- a/plugins/scaffolder-backend/src/service/rules.test.ts +++ b/plugins/scaffolder-backend/src/service/rules.test.ts @@ -22,10 +22,13 @@ import { hasProperty, hasStringProperty, hasTag, + isTaskOwner, } from './rules'; import { createConditionAuthorizer } from '@backstage/plugin-permission-node'; import { RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { SerializedTask } from '@backstage/plugin-scaffolder-node'; +import { TaskSpec } from '@backstage/plugin-scaffolder-common'; describe('hasTag', () => { describe('apply', () => { @@ -523,3 +526,77 @@ describe('hasStringProperty', () => { ); }); }); + +describe('isTaskOwner', () => { + describe('apply', () => { + const task: SerializedTask = { + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + createdBy: 'user:default/user-1', + }; + it('returns false when createdBy is an empty array', () => { + expect( + isTaskOwner.apply(task, { + createdBy: [], + }), + ).toEqual(false); + }); + it('returns false when createdBy is not matched (single user in createdBy)', () => { + expect( + isTaskOwner.apply(task, { + createdBy: ['not-matched'], + }), + ).toEqual(false); + }); + it('returns true when createdBy matches (single user in createdBy)', () => { + expect( + isTaskOwner.apply(task, { + createdBy: ['user:default/user-1'], + }), + ).toEqual(true); + }); + it('returns false when createdBy is not matched (multiple users in createdBy)', () => { + expect( + isTaskOwner.apply(task, { + createdBy: [ + 'user:default/user-2', + 'user:default/user-3', + 'user:default/user-4', + ], + }), + ).toEqual(false); + }); + it('returns true when createdBy matches (multiple users in createdBy)', () => { + expect( + isTaskOwner.apply(task, { + createdBy: [ + 'user:default/user-1', + 'user:default/user-2', + 'user:default/user-3', + ], + }), + ).toEqual(true); + }); + }); + describe('toQuery', () => { + it('returns the correct query filter with values (single user in createdBy)', () => { + expect( + isTaskOwner.toQuery({ + createdBy: ['user:default/user-1'], + }), + ).toEqual({ key: 'created_by', values: ['user:default/user-1'] }); + }); + }); + it('returns the correct query filter with values (multiple users in createdBy)', () => { + expect( + isTaskOwner.toQuery({ + createdBy: ['user:default/user-1', 'user:default/user-2'], + }), + ).toEqual({ + key: 'created_by', + values: ['user:default/user-1', 'user:default/user-2'], + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/service/rules.ts b/plugins/scaffolder-backend/src/service/rules.ts index b197810757..5753668089 100644 --- a/plugins/scaffolder-backend/src/service/rules.ts +++ b/plugins/scaffolder-backend/src/service/rules.ts @@ -15,9 +15,11 @@ */ import { makeCreatePermissionRule } from '@backstage/plugin-permission-node'; + import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, RESOURCE_TYPE_SCAFFOLDER_ACTION, + RESOURCE_TYPE_SCAFFOLDER_TASK, } from '@backstage/plugin-scaffolder-common/alpha'; import { @@ -25,6 +27,8 @@ import { TemplateParametersV1beta3, } from '@backstage/plugin-scaffolder-common'; +import { SerializedTask, TaskFilter } from '@backstage/plugin-scaffolder-node'; + import { z } from 'zod'; import { JsonObject, JsonPrimitive } from '@backstage/types'; import { get } from 'lodash'; @@ -129,6 +133,37 @@ function buildHasProperty<Schema extends z.ZodType<JsonPrimitive>>({ }); } +export const createTaskPermissionRule = makeCreatePermissionRule< + SerializedTask, + TaskFilter, + typeof RESOURCE_TYPE_SCAFFOLDER_TASK +>(); + +export const isTaskOwner = createTaskPermissionRule({ + name: 'IS_TASK_OWNER', + description: 'Allows tasks created by certain users to be accessible', + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, + paramsSchema: z.object({ + createdBy: z + .array(z.string()) + .describe( + 'List of creater entity refs; only tasks created by these users will be viewable', + ), + }), + apply: (resource, { createdBy }) => { + if (!resource.createdBy) { + return false; + } + return createdBy.includes(resource.createdBy); + }, + toQuery: ({ createdBy }) => { + return { + key: 'created_by', + values: createdBy, + }; + }, +}); + export const scaffolderTemplateRules = { hasTag }; export const scaffolderActionRules = { hasActionId, @@ -136,3 +171,4 @@ export const scaffolderActionRules = { hasNumberProperty, hasStringProperty, }; +export const scaffolderTaskRules = { isTaskOwner }; diff --git a/plugins/scaffolder-backend/src/util/checkPermissions.ts b/plugins/scaffolder-backend/src/util/checkPermissions.ts index b6c0395fbb..08a4ae1b13 100644 --- a/plugins/scaffolder-backend/src/util/checkPermissions.ts +++ b/plugins/scaffolder-backend/src/util/checkPermissions.ts @@ -21,7 +21,13 @@ import { NotAllowedError } from '@backstage/errors'; import { AuthorizeResult, BasicPermission, + PermissionCriteria, + PolicyDecision, + ResourcePermission, } from '@backstage/plugin-permission-common'; +import { ConditionTransformer } from '@backstage/plugin-permission-node'; +import { SerializedTask } from '@backstage/plugin-scaffolder-node'; +import { TaskFilters } from '@backstage/plugin-scaffolder-node'; export type checkPermissionOptions = { credentials: BackstageCredentials; @@ -29,6 +35,24 @@ export type checkPermissionOptions = { permissionService?: PermissionsService; }; +export type checkTaskPermissionOptions = { + credentials: BackstageCredentials; + permissions: ResourcePermission[]; + permissionService?: PermissionsService; + task: SerializedTask; + isTaskAuthorized: ( + decision: PolicyDecision, + resource: SerializedTask | undefined, + ) => boolean; +}; + +export type authorizeConditionsOptions = { + credentials: BackstageCredentials; + permission: ResourcePermission; + permissionService?: PermissionsService; + transformConditions: ConditionTransformer<TaskFilters>; +}; + /** * Does a basic check on permissions. Throws 403 error if any permission responds with AuthorizeResult.DENY * @public @@ -51,3 +75,55 @@ export async function checkPermission(options: checkPermissionOptions) { } } } + +/** + * Does a conditional permission check for scaffolder task reading and cancellation. + * Throws 403 error if permission responds with AuthorizeResult.DENY, or does not resolve to true during the conditional rule check + * @public + */ +export async function checkTaskPermission(options: checkTaskPermissionOptions) { + const { + permissions, + permissionService, + credentials, + task, + isTaskAuthorized, + } = options; + if (permissionService) { + const permissionRequest = permissions.map(permission => ({ + permission, + })); + const authorizationResponses = await permissionService.authorizeConditional( + permissionRequest, + { credentials }, + ); + for (const response of authorizationResponses) { + if ( + response.result === AuthorizeResult.DENY || + !isTaskAuthorized(response, task) + ) { + throw new NotAllowedError(); + } + } + } +} + +/** Fetches and transforms authorization conditions into filters, or returns `undefined` if the decision is not conditional. + * @public + */ +export const getAuthorizeConditions = async ( + options: authorizeConditionsOptions, +): Promise<PermissionCriteria<TaskFilters> | undefined> => { + const { permission, permissionService, credentials, transformConditions } = + options; + if (permissionService) { + const [taskDecision] = await permissionService.authorizeConditional( + [{ permission: permission }], + { credentials }, + ); + if (taskDecision.result === AuthorizeResult.CONDITIONAL) { + return transformConditions(taskDecision.conditions); + } + } + return undefined; +}; diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 5f1ed60113..b4b3316921 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-scaffolder-common +## 1.6.0 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + +## 1.6.0-next.1 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +## 1.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + ## 1.5.11 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 92e044898f..631c106ef3 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.5.11", + "version": "1.6.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-common/report-alpha.api.md b/plugins/scaffolder-common/report-alpha.api.md index 97a3de63c5..0bed459cc8 100644 --- a/plugins/scaffolder-common/report-alpha.api.md +++ b/plugins/scaffolder-common/report-alpha.api.md @@ -12,6 +12,9 @@ export const actionExecutePermission: ResourcePermission<'scaffolder-action'>; // @alpha export const RESOURCE_TYPE_SCAFFOLDER_ACTION = 'scaffolder-action'; +// @alpha +export const RESOURCE_TYPE_SCAFFOLDER_TASK = 'scaffolder-task'; + // @alpha export const RESOURCE_TYPE_SCAFFOLDER_TEMPLATE = 'scaffolder-template'; @@ -23,22 +26,26 @@ export const scaffolderPermissions: ( | BasicPermission | ResourcePermission<'scaffolder-action'> | ResourcePermission<'scaffolder-template'> + | ResourcePermission<'scaffolder-task'> )[]; // @alpha -export const scaffolderTaskPermissions: BasicPermission[]; +export const scaffolderTaskPermissions: ( + | BasicPermission + | ResourcePermission<'scaffolder-task'> +)[]; // @alpha export const scaffolderTemplatePermissions: ResourcePermission<'scaffolder-template'>[]; // @alpha -export const taskCancelPermission: BasicPermission; +export const taskCancelPermission: ResourcePermission<'scaffolder-task'>; // @alpha export const taskCreatePermission: BasicPermission; // @alpha -export const taskReadPermission: BasicPermission; +export const taskReadPermission: ResourcePermission<'scaffolder-task'>; // @alpha export const templateManagementPermission: BasicPermission; diff --git a/plugins/scaffolder-common/src/permissions.ts b/plugins/scaffolder-common/src/permissions.ts index e758291e75..36c72072e9 100644 --- a/plugins/scaffolder-common/src/permissions.ts +++ b/plugins/scaffolder-common/src/permissions.ts @@ -30,6 +30,13 @@ export const RESOURCE_TYPE_SCAFFOLDER_TEMPLATE = 'scaffolder-template'; */ export const RESOURCE_TYPE_SCAFFOLDER_ACTION = 'scaffolder-action'; +/** + * Permission resource type which corresponds to scaffolder tasks + * + * @alpha + */ +export const RESOURCE_TYPE_SCAFFOLDER_TASK = 'scaffolder-task'; + /** * This permission is used to authorize actions that involve executing * an action from a template. @@ -89,6 +96,7 @@ export const taskReadPermission = createPermission({ attributes: { action: 'read', }, + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, }); /** @@ -111,6 +119,7 @@ export const taskCreatePermission = createPermission({ export const taskCancelPermission = createPermission({ name: 'scaffolder.task.cancel', attributes: {}, + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, }); /** diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index bf20a8b4af..56c06b9cfc 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.3.1 + +### Patch Changes + +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- Updated dependencies + - @backstage/backend-test-utils@1.7.0 + - @backstage/plugin-scaffolder-node@0.10.0 + - @backstage/backend-plugin-api@1.4.1 + +## 0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.10.0-next.2 + +## 0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/backend-test-utils@1.7.0-next.1 + - @backstage/plugin-scaffolder-node@0.9.1-next.1 + +## 0.3.1-next.0 + +### Patch Changes + +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- Updated dependencies + - @backstage/backend-test-utils@1.7.0-next.0 + - @backstage/plugin-scaffolder-node@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + ## 0.3.0 ### Minor Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index 6275762142..8c13aab5aa 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.0", + "version": "0.3.1", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 5ed6355c8c..c69af2aefa 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/plugin-scaffolder-node +## 0.10.0 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/integration@1.17.1 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/backend-plugin-api@1.4.1 + +## 0.10.0-next.2 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + +## 0.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + +## 0.9.1-next.0 + +### Patch Changes + +- dbde180: An internal refactor which adds additional types to experimental checkpoints +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 0.9.0 ### Minor Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index cd03ead977..7e40332bf6 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.9.0", + "version": "0.10.0", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", @@ -58,6 +58,7 @@ "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/types": "workspace:^", "@isomorphic-git/pgp-plugin": "^0.0.7", diff --git a/plugins/scaffolder-node/report.api.md b/plugins/scaffolder-node/report.api.md index bceb9980b6..d0fd036f29 100644 --- a/plugins/scaffolder-node/report.api.md +++ b/plugins/scaffolder-node/report.api.md @@ -10,6 +10,7 @@ import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; import { LoggerService } from '@backstage/backend-plugin-api'; import { Observable } from '@backstage/types'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { Schema } from 'jsonschema'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { ScmIntegrations } from '@backstage/integration'; @@ -374,6 +375,7 @@ export interface TaskBroker { order: 'asc' | 'desc'; field: string; }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number; @@ -453,6 +455,25 @@ export interface TaskContext { // @public export type TaskEventType = 'completion' | 'log' | 'cancelled' | 'recovered'; +// @public +export type TaskFilter = { + key: string; + values?: string[]; +}; + +// @public +export type TaskFilters = + | { + anyOf: TaskFilter[]; + } + | { + allOf: TaskFilter[]; + } + | { + not: TaskFilter; + } + | TaskFilter; + // @public export type TaskSecrets = Record<string, string> & { backstageToken?: string; diff --git a/plugins/scaffolder-node/src/tasks/index.ts b/plugins/scaffolder-node/src/tasks/index.ts index 930de95237..7e93e84cc0 100644 --- a/plugins/scaffolder-node/src/tasks/index.ts +++ b/plugins/scaffolder-node/src/tasks/index.ts @@ -18,6 +18,8 @@ export type { TaskSecrets, SerializedTask, SerializedTaskEvent, + TaskFilter, + TaskFilters, TaskBroker, TaskBrokerDispatchOptions, TaskBrokerDispatchResult, diff --git a/plugins/scaffolder-node/src/tasks/types.ts b/plugins/scaffolder-node/src/tasks/types.ts index d2403f205a..b55a2729b7 100644 --- a/plugins/scaffolder-node/src/tasks/types.ts +++ b/plugins/scaffolder-node/src/tasks/types.ts @@ -15,6 +15,7 @@ */ import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { JsonObject, Observable } from '@backstage/types'; import { UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node/alpha'; @@ -105,6 +106,25 @@ export type TaskBrokerDispatchOptions = { createdBy?: string; }; +/** + * TaskFilter + * @public + */ +export type TaskFilter = { + key: string; + values?: string[]; +}; + +/** + * TaskFilters + * @public + */ +export type TaskFilters = + | { anyOf: TaskFilter[] } + | { allOf: TaskFilter[] } + | { not: TaskFilter } + | TaskFilter; + /** * Task * @@ -183,6 +203,7 @@ export interface TaskBroker { offset?: number; }; order?: { order: 'asc' | 'desc'; field: string }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }>; /** diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index cd44a6cbc0..c165815d17 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,88 @@ # @backstage/plugin-scaffolder-react +## 1.18.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 1.18.0 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- 94c11a5: Scroll to the top of the page when navigating between steps in template forms. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-permission-react@0.4.36 + +## 1.18.0-next.2 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- 94c11a5: Scroll to the top of the page when navigating between steps in template forms. +- Updated dependencies + - @backstage/theme@0.6.7-next.1 + - @backstage/core-components@0.17.4-next.2 + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + +## 1.17.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.17.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 1.17.0 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index b4adfd9c50..fc2437793a 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.17.0", + "version": "1.18.1-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/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx index 9546792983..2df4ff3b71 100644 --- a/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx +++ b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx @@ -30,7 +30,6 @@ import Functions from '@material-ui/icons/Functions'; import MoreVert from '@material-ui/icons/MoreVert'; import { SyntheticEvent, useState } from 'react'; import { usePermission } from '@backstage/plugin-permission-react'; -import { taskReadPermission } from '@backstage/plugin-scaffolder-common/alpha'; import { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha'; import { scaffolderReactTranslationRef } from '../../../translation'; @@ -69,10 +68,6 @@ export function ScaffolderPageContextMenu( const classes = useStyles(); const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>(); - const { allowed: canReadTasks } = usePermission({ - permission: taskReadPermission, - }); - const { allowed: canManageTemplates } = usePermission({ permission: templateManagementPermission, }); @@ -164,7 +159,7 @@ export function ScaffolderPageContextMenu( /> </MenuItem> )} - {onTasksClicked && canReadTasks && ( + {onTasksClicked && ( <MenuItem onClick={onTasksClicked}> <ListItemIcon> <List fontSize="small" /> 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 af9117ccf5..b0746e0672 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -672,6 +672,40 @@ describe('Stepper', () => { ); }); + it('should scroll the first main element to top when activeStep changes', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { title: 'Step 1', schema: { properties: {} } }, + { title: 'Step 2', schema: { properties: {} } }, + ], + title: 'Scroll Test', + }; + + // Render a main element in the document for the Stepper to find + const main = document.createElement('main'); + document.body.appendChild(main); + const scrollToMock = jest.fn(); + main.scrollTo = scrollToMock; + + // Render Stepper as usual (do not pass container) + const { getByRole, unmount } = await renderInTestApp( + <SecretsContextProvider> + <Stepper manifest={manifest} extensions={[]} onCreate={jest.fn()} /> + </SecretsContextProvider>, + ); + + // Click next to change the activeStep + await act(async () => { + fireEvent.click(getByRole('button', { name: 'Next' })); + }); + + expect(scrollToMock).toHaveBeenCalledWith({ top: 0, behavior: 'auto' }); + + // Clean up + document.body.removeChild(main); + unmount(); + }); + describe('Scaffolder Layouts', () => { it('should render the step in the scaffolder layout', async () => { const ScaffolderLayout: LayoutTemplate = ({ properties }) => ( diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 6715eb0e1e..1f36eb58d3 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -37,6 +37,7 @@ import { merge } from 'lodash'; import { ComponentType, useCallback, + useEffect, useMemo, useState, type ReactNode, @@ -218,6 +219,13 @@ export const Stepper = (stepperProps: StepperProps) => { [validation, analytics], ); + useEffect(() => { + const main = document.querySelector('main'); + if (main && typeof main.scrollTo === 'function') { + main.scrollTo({ top: 0, behavior: 'auto' }); + } + }, [activeStep]); + const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema); const [isCreating, setIsCreating] = useState(false); diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index a9fcc8001e..8a77e9fe8a 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-scaffolder +## 1.33.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/plugin-scaffolder-react@1.18.1-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + +## 1.33.0 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- 289e4a1: Filter MultiEntityPicker options based on rendered option value +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-scaffolder-react@1.18.0 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + - @backstage/plugin-scaffolder-common@1.6.0 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + +## 1.33.0-next.2 + +### Minor Changes + +- c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions. + + BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators. + + BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.18.0-next.2 + - @backstage/core-components@0.17.4-next.2 + - @backstage/plugin-scaffolder-common@1.6.0-next.1 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + +## 1.32.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-permission-react@0.4.36-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-scaffolder-common@1.5.12-next.0 + - @backstage/plugin-scaffolder-react@1.17.1-next.1 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.32.1-next.0 + +### Patch Changes + +- 289e4a1: Filter MultiEntityPicker options based on rendered option value +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/integration-react@1.2.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/plugin-scaffolder-react@1.17.1-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 1.32.0 ### Minor Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 2cbe62cdbf..6027359335 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.32.0", + "version": "1.33.1-next.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.test.tsx index 879f225b4e..0f3237547a 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.test.tsx @@ -99,7 +99,6 @@ describe('TemplateEditorToolbarTemplatesMenu', () => { name: 'Publish', action: 'publish:github', input: { - allowedHosts: ['github.com'], description: 'This is ${{ parameters.component_id }}', repoUrl: '${{ parameters.repoUrl }}', }, @@ -205,7 +204,6 @@ describe('TemplateEditorToolbarTemplatesMenu', () => { name: 'Publish', action: 'publish:github', input: { - allowedHosts: ['github.com'], description: 'This is ${{ parameters.component_id }}', repoUrl: '${{ parameters.repoUrl }}', }, diff --git a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx index 6d48cec125..d6b5b7116e 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx @@ -91,14 +91,22 @@ const ListTaskPageContent = (props: MyTaskPageProps) => { if (error) { return ( - <> - <ErrorPanel error={error} /> - <EmptyState - missing="info" - title={t('listTaskPage.content.emptyState.title')} - description={t('listTaskPage.content.emptyState.description')} - /> - </> + <CatalogFilterLayout> + <CatalogFilterLayout.Filters> + <OwnerListPicker + filter={ownerFilter} + onSelectOwner={id => setOwnerFilter(id)} + /> + </CatalogFilterLayout.Filters> + <CatalogFilterLayout.Content> + <ErrorPanel error={error} /> + <EmptyState + missing="info" + title={t('listTaskPage.content.emptyState.title')} + description={t('listTaskPage.content.emptyState.description')} + /> + </CatalogFilterLayout.Content> + </CatalogFilterLayout> ); } diff --git a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx index e1a5f37ddc..2df1fc4ddb 100644 --- a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx @@ -46,6 +46,7 @@ type ContextMenuProps = { onStartOver?: () => void; onToggleLogs?: (state: boolean) => void; onToggleButtonBar?: (state: boolean) => void; + taskId?: string; isCancelButtonDisabled: boolean; onCancel: () => void; }; @@ -67,6 +68,7 @@ export const ContextMenu = (props: ContextMenuProps) => { onStartOver, onToggleLogs, onToggleButtonBar, + taskId, } = props; const { getPageTheme } = useTheme(); const pageTheme = getPageTheme({ themeId: 'website' }); @@ -76,6 +78,7 @@ export const ContextMenu = (props: ContextMenuProps) => { const { allowed: canReadTask } = usePermission({ permission: taskReadPermission, + resourceRef: taskId, }); const { allowed: canCreateTask } = usePermission({ diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx index a576b1a9bc..5e44d5cf43 100644 --- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx @@ -161,20 +161,43 @@ describe('OngoingTask', () => { await expect(rendered.findByText('Hide Logs')).resolves.toBeInTheDocument(); }); - it('should have cancel and start over buttons be disabled without the proper permissions', async () => { + it('should have cancel button be disabled when user has read permission but lacks cancel permission', async () => { const permissionApi = mockApis.permission({ - authorize: AuthorizeResult.DENY, + authorize: request => { + if (request.permission.name === 'scaffolder.task.cancel') { + return AuthorizeResult.DENY; + } + return AuthorizeResult.ALLOW; + }, }); const rendered = await render(permissionApi); const { getByTestId } = rendered; expect(getByTestId('cancel-button')).toHaveClass('Mui-disabled'); - expect(getByTestId('start-over-button')).toHaveClass('Mui-disabled'); await act(async () => { fireEvent.click(getByTestId('menu-button')); }); expect(getByTestId('cancel-task')).toHaveClass('Mui-disabled'); - expect(getByTestId('start-over-task')).toHaveClass('Mui-disabled'); + }); + + it('should have start over button be disabled when user has read permission but lacks create permission', async () => { + const permissionApi = mockApis.permission({ + authorize: request => { + if (request.permission.name === 'scaffolder.task.create') { + return AuthorizeResult.DENY; + } + return AuthorizeResult.ALLOW; + }, + }); + const rendered = await render(permissionApi); + + const { getByTestId } = rendered; + expect(getByTestId('start-over-button')).toHaveClass('Mui-disabled'); + + await act(async () => { + fireEvent.click(getByTestId('menu-button')); + }); + expect(getByTestId('start-over-button')).toHaveClass('Mui-disabled'); }); }); diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx index c9a119e4a1..bc0d5fe1aa 100644 --- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx @@ -139,13 +139,14 @@ function OngoingTaskContent(props: { const [logsVisible, setLogVisibleState] = useState(false); const [buttonBarVisible, setButtonBarVisibleState] = useState(true); - // Used dummy string value for `resourceRef` since `allowed` field will always return `false` if `resourceRef` is `undefined` const { allowed: canCancelTask } = usePermission({ permission: taskCancelPermission, + resourceRef: taskId, }); const { allowed: canReadTask } = usePermission({ permission: taskReadPermission, + resourceRef: taskId, }); const { allowed: canCreateTask } = usePermission({ @@ -269,6 +270,7 @@ function OngoingTaskContent(props: { onRetry={triggerRetry} onToggleLogs={setLogVisibleState} onToggleButtonBar={setButtonBarVisibleState} + taskId={taskId} onCancel={triggerCancel} isCancelButtonDisabled={isCancelButtonDisabled} /> diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index 91567c1ddd..d8dee73849 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -60,10 +60,7 @@ import { CustomFieldsPage, } from '../../alpha/components/TemplateEditorPage'; import { RequirePermission } from '@backstage/plugin-permission-react'; -import { - taskReadPermission, - templateManagementPermission, -} from '@backstage/plugin-scaffolder-common/alpha'; +import { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha'; import { useApp } from '@backstage/core-plugin-api'; import { FormField, OpaqueFormField } from '@internal/scaffolder'; import { useAsync, useMountEffect } from '@react-hookz/web'; @@ -182,11 +179,9 @@ export const InternalRouter = ( <Route path={scaffolderTaskRouteRef.path} element={ - <RequirePermission permission={taskReadPermission}> - <TaskPageComponent - TemplateOutputsComponent={TemplateOutputsComponent} - /> - </RequirePermission> + <TaskPageComponent + TemplateOutputsComponent={TemplateOutputsComponent} + /> } /> <Route @@ -230,11 +225,7 @@ export const InternalRouter = ( /> <Route path={scaffolderListTaskRouteRef.path} - element={ - <RequirePermission permission={taskReadPermission}> - <ListTasksPage contextMenu={props.contextMenu} /> - </RequirePermission> - } + element={<ListTasksPage contextMenu={props.contextMenu} />} /> <Route path={editorRouteRef.path} diff --git a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.test.tsx index acae3418b9..a02d793a34 100644 --- a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.test.tsx @@ -947,4 +947,81 @@ describe('<MultiEntityPicker />', () => { expect(getByText(description.fromUiSchema)).toBeInTheDocument(); }); }); + + describe('entity presentation', () => { + beforeEach(() => { + uiSchema = { + 'ui:options': { + defaultKind: 'Group', + }, + }; + props = { + onChange, + schema, + required, + uiSchema, + rawErrors, + formData, + } as unknown as FieldProps<any>; + }); + + it('renders and filters selection displayName', async () => { + catalogApi.getEntities.mockResolvedValue({ + items: entities.map(item => ({ + ...item, + spec: { + profile: { displayName: item.metadata.name.replace('-', ' ') }, + }, + })), + }); + + const { getByRole, getByText } = await renderInTestApp( + <Wrapper> + <MultiEntityPicker {...props} /> + </Wrapper>, + ); + + const input = getByRole('textbox'); + + fireEvent.change(input, { target: { value: 'team a' } }); + + expect(getByText('team a')).toBeInTheDocument(); + + fireEvent.change(input, { target: { value: 'squad b' } }); + + expect(getByText('squad b')).toBeInTheDocument(); + + fireEvent.blur(input); + }); + + it('renders and filters selection title', async () => { + catalogApi.getEntities.mockResolvedValue({ + items: entities.map(item => ({ + ...item, + metadata: { + ...item.metadata, + title: item.metadata.name.replace('-', ' ').toUpperCase(), + }, + })), + }); + + const { getByRole, getByText } = await renderInTestApp( + <Wrapper> + <MultiEntityPicker {...props} /> + </Wrapper>, + ); + + const input = getByRole('textbox'); + + fireEvent.change(input, { target: { value: 'team a' } }); + + expect(getByText('TEAM A')).toBeInTheDocument(); + + fireEvent.change(input, { target: { value: 'squad b' } }); + + expect(getByText('SQUAD B')).toBeInTheDocument(); + + fireEvent.blur(input); + }); + }); }); diff --git a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx index e7dcf0f996..57c4b87d6d 100644 --- a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx @@ -32,6 +32,7 @@ import { import TextField from '@material-ui/core/TextField'; import Autocomplete, { AutocompleteChangeReason, + createFilterOptions, } from '@material-ui/lab/Autocomplete'; import { useCallback, useEffect, useState } from 'react'; import useAsync from 'react-use/esm/useAsync'; @@ -203,6 +204,11 @@ export const MultiEntityPicker = (props: MultiEntityPickerProps) => { }} /> )} + filterOptions={createFilterOptions<Entity>({ + stringify: option => + entities?.entityRefToPresentation.get(stringifyEntityRef(option)) + ?.primaryTitle!, + })} ListboxComponent={VirtualizedListbox} /> </ScaffolderField> diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 14cb48f3a0..37a3391656 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-search-backend-module-catalog +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 0.3.5 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 46782aac2f..45ad15246f 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.3.5", + "version": "0.3.6", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 26cc4c5390..4e277847ac 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.7.4 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 1.7.4-next.0 + +### Patch Changes + +- 3507fcd: Just some more circular dep cleanup +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/integration-aws-node@0.1.17-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 1.7.3 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index cd1d8588d2..e472374460 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.7.3", + "version": "1.7.4", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/report.api.md b/plugins/search-backend-module-elasticsearch/report.api.md index 9250cfda31..19c44bd566 100644 --- a/plugins/search-backend-module-elasticsearch/report.api.md +++ b/plugins/search-backend-module-elasticsearch/report.api.md @@ -11,7 +11,6 @@ import { BulkHelper } from '@elastic/elasticsearch/lib/Helpers'; import { BulkStats } from '@elastic/elasticsearch/lib/Helpers'; import { Config } from '@backstage/config'; import type { ConnectionOptions } from 'tls'; -import { ElasticSearchQueryTranslator as ElasticSearchQueryTranslator_2 } from '@backstage/plugin-search-backend-module-elasticsearch'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { IndexableDocument } from '@backstage/plugin-search-common'; import { IndexableResultSet } from '@backstage/plugin-search-common'; @@ -332,7 +331,7 @@ export type ElasticSearchQueryTranslator = ( // @public (undocumented) export interface ElasticSearchQueryTranslatorExtensionPoint { // (undocumented) - setTranslator(translator: ElasticSearchQueryTranslator_2): void; + setTranslator(translator: ElasticSearchQueryTranslator): void; } // @public diff --git a/plugins/search-backend-module-elasticsearch/src/module.ts b/plugins/search-backend-module-elasticsearch/src/module.ts index c5c2a6fc1d..d4ce249093 100644 --- a/plugins/search-backend-module-elasticsearch/src/module.ts +++ b/plugins/search-backend-module-elasticsearch/src/module.ts @@ -22,7 +22,7 @@ import { searchEngineRegistryExtensionPoint } from '@backstage/plugin-search-bac import { ElasticSearchQueryTranslator, ElasticSearchSearchEngine, -} from '@backstage/plugin-search-backend-module-elasticsearch'; +} from './engines/ElasticSearchSearchEngine'; /** @public */ export interface ElasticSearchQueryTranslatorExtensionPoint { diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 074df19408..e066fcacd4 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-search-backend-module-explore +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 0.3.3 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index e2d1bd81f7..01e02aafea 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.3.3", + "version": "0.3.4", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index d485ba36f7..52bb74b2ea 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.46 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 0.5.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 0.5.45 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 256f4d360b..d306f82a21 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.45", + "version": "0.5.46", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 9e29c90271..1c6ba9b47f 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 0.3.10 ### Patch Changes diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json index 7fff2d51f8..afec8e0856 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.3.10", + "version": "0.3.11", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index bafe7a3598..61d24321eb 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/plugin-techdocs-node@1.13.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-techdocs-node@1.13.5-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + +## 0.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-techdocs-node@1.13.5-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-common@1.2.18 + ## 0.4.3 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index 2d79594425..3dca92a229 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.4.3", + "version": "0.4.4", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 4011f37d73..a738b22c1d 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-search-backend-node +## 1.3.13 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-search-common@1.2.19 + +## 1.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + ## 1.3.12 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 8a9bb61c1e..601f3c3451 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.3.12", + "version": "1.3.13", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index e82e398599..a46ca82fba 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-search-backend +## 2.0.4 + +### Patch Changes + +- 69fb975: Error messages should not contain backend SQL query strings in the API response, this change will ensure that messages are logged and empty response is returned to the user +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-node@0.10.2 + - @backstage/backend-defaults@0.11.1 + - @backstage/backend-openapi-utils@0.5.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-search-backend-node@1.3.13 + - @backstage/plugin-search-common@1.2.19 + +## 2.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/plugin-permission-node@0.10.2-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-node@1.3.13-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + - @backstage/backend-openapi-utils@0.5.5-next.0 + +## 2.0.4-next.0 + +### Patch Changes + +- 69fb975: Error messages should not contain backend SQL query strings in the API response, this change will ensure that messages are logged and empty response is returned to the user +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-common@1.2.18 + ## 2.0.3 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 02acb8dd77..f1566d80af 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "2.0.3", + "version": "2.0.4", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index e6f08e2183..ef5deee025 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-common +## 1.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + +## 1.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + ## 1.2.18 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index 1c68dd7762..582e6b3434 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-common", - "version": "1.2.18", + "version": "1.2.19", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", "backstage": { "role": "common-library", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 157a5664a9..6fa747f6f8 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-search-react +## 1.9.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-search-common@1.2.19 + +## 1.9.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.9.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + ## 1.9.1 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 2d0617a6b3..3c42a63543 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.9.1", + "version": "1.9.2", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 7d6e4248de..32cee06208 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-search +## 1.4.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-search-react@1.9.2 + +## 1.4.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-search-react@1.9.2 + +## 1.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/plugin-search-react@1.9.2-next.0 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + ## 1.4.27 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 56382bc5ee..dade090577 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.27", + "version": "1.4.29-next.0", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index daa8f03014..b2d184ab51 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-signals-backend +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-events-node@0.4.13 + - @backstage/plugin-signals-node@0.1.22 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-signals-node@0.1.22-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.3.5 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 04dcdc60d2..761c8e8ad9 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.5", + "version": "0.3.6", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index d24f1cc0b1..080639e506 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-signals-node +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-events-node@0.4.13 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.1.21 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 15472a930d..4ce0cb7370 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.21", + "version": "0.1.22", "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 223dfed79c..d5cfb09e39 100644 --- a/plugins/signals-react/CHANGELOG.md +++ b/plugins/signals-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-signals-react +## 0.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.9 + +## 0.0.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.9-next.0 + ## 0.0.14 ### Patch Changes diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json index d8bf9d4e0f..cc92bb120c 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.14", + "version": "0.0.15", "description": "Web library for the signals plugin", "backstage": { "role": "web-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index ce4971a5d9..df17a33f5d 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-signals +## 0.0.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.0.21 + +### Patch Changes + +- d52d67f: Added a New Frontend System App Root Element for the `<SignalsDisplay />` component +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-signals-react@0.0.15 + +## 0.0.21-next.2 + +### Patch Changes + +- d52d67f: Added a New Frontend System App Root Element for the `<SignalsDisplay />` component +- Updated dependencies + - @backstage/theme@0.6.7-next.1 + - @backstage/core-components@0.17.4-next.2 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + +## 0.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + - @backstage/plugin-signals-react@0.0.15-next.0 + +## 0.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + ## 0.0.20 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index dd025dfbb2..ccf108f3d8 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.20", + "version": "0.0.22-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "signals", @@ -51,6 +51,7 @@ "test": "backstage-cli package test" }, "dependencies": { + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/signals/report-alpha.api.md b/plugins/signals/report-alpha.api.md index 45ee0da3b8..3fc89308c1 100644 --- a/plugins/signals/report-alpha.api.md +++ b/plugins/signals/report-alpha.api.md @@ -7,6 +7,7 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; +import { JSX as JSX_2 } from 'react'; // @alpha (undocumented) const _default: FrontendPlugin< @@ -28,6 +29,21 @@ const _default: FrontendPlugin< factory: AnyApiFactory; }; }>; + 'app-root-element:signals/signals-display': ExtensionDefinition<{ + kind: 'app-root-element'; + name: 'signals-display'; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + {} + >; + inputs: {}; + params: { + element: JSX.Element | (() => JSX.Element); + }; + }>; } >; export default _default; diff --git a/plugins/signals/src/alpha.tsx b/plugins/signals/src/alpha.tsx index 90b78b05fd..38955473e1 100644 --- a/plugins/signals/src/alpha.tsx +++ b/plugins/signals/src/alpha.tsx @@ -16,6 +16,7 @@ import { ApiBlueprint, + AppRootElementBlueprint, createApiFactory, createFrontendPlugin, discoveryApiRef, @@ -23,6 +24,8 @@ import { } from '@backstage/frontend-plugin-api'; import { signalApiRef } from '@backstage/plugin-signals-react'; import { SignalClient } from './api/SignalClient'; +import { SignalsDisplay } from './plugin'; +import { compatWrapper } from '@backstage/core-compat-api'; const api = ApiBlueprint.make({ params: { @@ -42,9 +45,16 @@ const api = ApiBlueprint.make({ }, }); +const signalsDisplayAppRootElement = AppRootElementBlueprint.make({ + name: 'signals-display', + params: { + element: compatWrapper(<SignalsDisplay />), + }, +}); + /** @alpha */ export default createFrontendPlugin({ pluginId: 'signals', info: { packageJson: () => import('../package.json') }, - extensions: [api], + extensions: [api, signalsDisplayAppRootElement], }); diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 1df73776db..31c4220e99 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,74 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.52-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/plugin-catalog@1.31.2-next.0 + - @backstage/plugin-techdocs@1.13.3-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/plugin-search-react@1.9.2 + +## 1.0.51 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.13.2 + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/plugin-catalog@1.31.1 + - @backstage/core-plugin-api@1.10.9 + - @backstage/core-app-api@1.18.0 + - @backstage/integration-react@1.2.9 + - @backstage/test-utils@1.7.10 + - @backstage/plugin-search-react@1.9.2 + - @backstage/plugin-techdocs-react@1.3.1 + +## 1.0.51-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.18.0-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/test-utils@1.7.10-next.2 + - @backstage/plugin-catalog@1.31.1-next.2 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + - @backstage/plugin-techdocs@1.13.2-next.1 + +## 1.0.51-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-app-api@1.17.2-next.0 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/test-utils@1.7.10-next.1 + - @backstage/plugin-techdocs@1.13.2-next.1 + - @backstage/plugin-techdocs-react@1.3.1-next.1 + - @backstage/plugin-catalog@1.31.1-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + +## 1.0.51-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.13.2-next.0 + - @backstage/integration-react@1.2.9-next.0 + - @backstage/plugin-catalog@1.31.1-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/test-utils@1.7.10-next.0 + - @backstage/plugin-search-react@1.9.2-next.0 + - @backstage/plugin-techdocs-react@1.3.1-next.0 + - @backstage/core-app-api@1.17.1 + - @backstage/core-plugin-api@1.10.8 + ## 1.0.49 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index c10539afeb..a7e6b4967d 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.49", + "version": "1.0.52-next.0", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index f4d3b62cca..569acfc446 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-techdocs-backend +## 2.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/catalog-model@1.7.5 + - @backstage/backend-defaults@0.11.1 + - @backstage/catalog-client@1.10.2 + - @backstage/integration@1.17.1 + - @backstage/plugin-techdocs-node@1.13.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-catalog-node@1.17.2 + - @backstage/plugin-search-backend-module-techdocs@0.4.4 + +## 2.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/plugin-permission-common@0.9.1-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/integration@1.17.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.4-next.1 + - @backstage/plugin-techdocs-node@1.13.5-next.1 + - @backstage/plugin-catalog-common@1.1.5-next.0 + - @backstage/plugin-catalog-node@1.17.2-next.0 + +## 2.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-search-backend-module-techdocs@0.4.4-next.0 + - @backstage/plugin-techdocs-node@1.13.5-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-techdocs-common@0.1.1 + ## 2.0.3 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 00135b3535..9ef73636d6 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "2.0.3", + "version": "2.0.4", "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 6cb56e3184..374da3cd69 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-techdocs-react@1.3.1 + +## 1.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-techdocs-react@1.3.1-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/integration-react@1.2.9-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/plugin-techdocs-react@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + ## 1.1.25 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index bede6d623c..48af21e1b2 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.25", + "version": "1.1.26", "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 c44b7fca9e..f4e3d705f2 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-techdocs-node +## 1.13.5 + +### Patch Changes + +- 029526c: Updated the error message thrown by parseReferenceAnnotation to reflect the annotation value passed as an argument rather than in correctly assuming location. +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-search-common@1.2.19 + +## 1.13.5-next.2 + +### Patch Changes + +- 029526c: Updated the error message thrown by parseReferenceAnnotation to reflect the annotation value passed as an argument rather than in correctly assuming location. + +## 1.13.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/integration-aws-node@0.1.17-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-search-common@1.2.19-next.0 + +## 1.13.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.13.4 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 9616553217..832ba0c652 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.4", + "version": "1.13.5", "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-node/src/helpers.test.ts b/plugins/techdocs-node/src/helpers.test.ts index 33f4018f47..aa1aa69d30 100644 --- a/plugins/techdocs-node/src/helpers.test.ts +++ b/plugins/techdocs-node/src/helpers.test.ts @@ -113,9 +113,12 @@ describe('parseReferenceAnnotation', () => { }); it('should throw error without annotation', () => { + const logMsgRegex = new RegExp( + `No ${TECHDOCS_ANNOTATION} annotation provided`, + ); expect(() => { parseReferenceAnnotation(TECHDOCS_ANNOTATION, entityBase); - }).toThrow(/No location annotation/); + }).toThrow(logMsgRegex); }); it('should throw error with bad annotation', () => { diff --git a/plugins/techdocs-node/src/helpers.ts b/plugins/techdocs-node/src/helpers.ts index 67bb862c62..f1655aa9a6 100644 --- a/plugins/techdocs-node/src/helpers.ts +++ b/plugins/techdocs-node/src/helpers.ts @@ -52,7 +52,7 @@ export const parseReferenceAnnotation = ( const annotation = entity.metadata.annotations?.[annotationName]; if (!annotation) { throw new InputError( - `No location annotation provided in entity: ${entity.metadata.name}`, + `No ${annotationName} annotation provided in entity: ${entity.metadata.name}`, ); } diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index bc8c2a7bff..9b9cef6283 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-techdocs-react +## 1.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/frontend-plugin-api@0.10.4 + +## 1.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/frontend-plugin-api@0.10.4-next.1 + +## 1.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.3.0 ### Minor Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 94494a7266..4eef91ef52 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.0", + "version": "1.3.1", "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 8ff3635285..5dfc9388fb 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,82 @@ # @backstage/plugin-techdocs +## 1.13.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/integration-react@1.2.9 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-search-react@1.9.2 + +## 1.13.2 + +### Patch Changes + +- 1debf7f: Fixed an issue causing TechDocs to not properly handle initial redirect. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/config@1.3.3 + - @backstage/catalog-model@1.7.5 + - @backstage/catalog-client@1.10.2 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration@1.17.1 + - @backstage/theme@0.6.7 + - @backstage/integration-react@1.2.9 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-auth-react@0.1.17 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-search-react@1.9.2 + - @backstage/plugin-techdocs-react@1.3.1 + +## 1.13.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/catalog-client@1.10.2-next.0 + - @backstage/integration@1.17.1-next.1 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/integration-react@1.2.9-next.1 + - @backstage/plugin-techdocs-react@1.3.1-next.1 + - @backstage/plugin-search-common@1.2.19-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/plugin-search-react@1.9.2-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + - @backstage/plugin-auth-react@0.1.17-next.1 + +## 1.13.2-next.0 + +### Patch Changes + +- 1debf7f: Fixed an issue causing TechDocs to not properly handle initial redirect. +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/integration-react@1.2.9-next.0 + - @backstage/theme@0.6.7-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/plugin-search-react@1.9.2-next.0 + - @backstage/plugin-techdocs-react@1.3.1-next.0 + - @backstage/catalog-client@1.10.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/plugin-auth-react@0.1.17-next.0 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.13.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 40ed4856bf..d3a5f9ac93 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.13.0", + "version": "1.13.3-next.0", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 2139fc3f72..562899a2ce 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-user-settings-backend +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-auth-node@0.6.5 + - @backstage/plugin-signals-node@0.1.22 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.1 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-auth-node@0.6.5-next.0 + - @backstage/plugin-signals-node@0.1.22-next.0 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.1-next.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-node@0.1.21 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.3.3 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 992f3ce5ed..1a1e872edd 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.3", + "version": "0.3.4", "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 036af600c6..cf8f98617a 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-user-settings +## 0.8.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.2-next.0 + - @backstage/core-compat-api@0.4.5-next.0 + - @backstage/frontend-plugin-api@0.10.4 + +## 0.8.24 + +### Patch Changes + +- aa3b054: Added `signIn` and `signOut` analytic events to the `@backstage/core-components` of sign in and sign out. +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.1 + - @backstage/catalog-model@1.7.5 + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + - @backstage/theme@0.6.7 + - @backstage/core-app-api@1.18.0 + - @backstage/core-compat-api@0.4.4 + - @backstage/frontend-plugin-api@0.10.4 + - @backstage/plugin-signals-react@0.0.15 + +## 0.8.24-next.2 + +### Patch Changes + +- aa3b054: Added `signIn` and `signOut` analytic events to the `@backstage/core-components` of sign in and sign out. +- Updated dependencies + - @backstage/theme@0.6.7-next.1 + - @backstage/core-app-api@1.18.0-next.1 + - @backstage/core-components@0.17.4-next.2 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + +## 0.8.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.1 + - @backstage/core-app-api@1.17.2-next.0 + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + - @backstage/core-compat-api@0.4.4-next.1 + - @backstage/frontend-plugin-api@0.10.4-next.1 + - @backstage/plugin-signals-react@0.0.15-next.0 + +## 0.8.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.7-next.0 + - @backstage/plugin-catalog-react@1.19.1-next.0 + - @backstage/core-components@0.17.4-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.4-next.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/frontend-plugin-api@0.10.4-next.0 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.23 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 2ae1c9991d..b4b6d4e83d 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.23", + "version": "0.8.25-next.0", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings/src/components/General/UserSettingsMenu.tsx b/plugins/user-settings/src/components/General/UserSettingsMenu.tsx index 6fb55896e9..dc954e862f 100644 --- a/plugins/user-settings/src/components/General/UserSettingsMenu.tsx +++ b/plugins/user-settings/src/components/General/UserSettingsMenu.tsx @@ -25,6 +25,7 @@ import { identityApiRef, errorApiRef, useApi, + useAnalytics, } from '@backstage/core-plugin-api'; import { useTranslationRef } from '@backstage/frontend-plugin-api'; import { userSettingsTranslationRef } from '../../translation'; @@ -36,6 +37,7 @@ export const UserSettingsMenu = () => { const [open, setOpen] = useState(false); const [anchorEl, setAnchorEl] = useState<undefined | HTMLElement>(undefined); const { t } = useTranslationRef(userSettingsTranslationRef); + const analytics = useAnalytics(); const handleOpen = (event: MouseEvent<HTMLButtonElement>) => { setAnchorEl(event.currentTarget); @@ -59,9 +61,10 @@ export const UserSettingsMenu = () => { <Menu anchorEl={anchorEl} open={open} onClose={handleClose}> <MenuItem data-testid="sign-out" - onClick={() => - identityApi.signOut().catch(error => errorApi.post(error)) - } + onClick={() => { + identityApi.signOut().catch(error => errorApi.post(error)); + analytics.captureEvent('signOut', 'success'); + }} > <ListItemIcon> <SignOutIcon /> diff --git a/yarn.lock b/yarn.lock index 696e4023cd..16d15bea2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2148,17 +2148,17 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-string-parser@npm:7.25.9" - checksum: 10/c28656c52bd48e8c1d9f3e8e68ecafd09d949c57755b0d353739eb4eae7ba4f7e67e92e4036f1cd43378cc1397a2c943ed7bcaf5949b04ab48607def0258b775 +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10/0ae29cc2005084abdae2966afdb86ed14d41c9c37db02c3693d5022fba9f5d59b011d039380b8e537c34daf117c549f52b452398f576e908fb9db3c7abbb3a00 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-identifier@npm:7.25.9" - checksum: 10/3f9b649be0c2fd457fa1957b694b4e69532a668866b8a0d81eabfa34ba16dbf3107b39e0e7144c55c3c652bf773ec816af8df4a61273a2bb4eb3145ca9cf478e +"@babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.25.9, @babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10/75041904d21bdc0cd3b07a8ac90b11d64cd3c881e89cb936fa80edd734bf23c35e6bd1312611e8574c4eab1f3af0f63e8a5894f4699e9cfdf70c06fcf4252320 languageName: node linkType: hard @@ -2202,14 +2202,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.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.27.0": - version: 7.27.0 - resolution: "@babel/parser@npm:7.27.0" +"@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.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.26.7, @babel/parser@npm:^7.27.0, @babel/parser@npm:^7.27.5": + version: 7.27.5 + resolution: "@babel/parser@npm:7.27.5" dependencies: - "@babel/types": "npm:^7.27.0" + "@babel/types": "npm:^7.27.3" bin: parser: ./bin/babel-parser.js - checksum: 10/0fee9f05c6db753882ca9d10958301493443da9f6986d7020ebd7a696b35886240016899bc0b47d871aea2abcafd64632343719742e87432c8145e0ec2af2a03 + checksum: 10/0ad671be7994dba7d31ec771bd70ea5090aa34faf73e93b1b072e3c0a704ab69f4a7a68ebfb9d6a7fa455e0aa03dfa65619c4df6bae1cf327cba925b1d233fc4 languageName: node linkType: hard @@ -3370,13 +3370,13 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.27.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.27.0 - resolution: "@babel/types@npm:7.27.0" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.27.0, @babel/types@npm:^7.27.3, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.27.6 + resolution: "@babel/types@npm:7.27.6" dependencies: - "@babel/helper-string-parser": "npm:^7.25.9" - "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/2c322bce107c8a534dc4a23be60d570e6a4cc7ca2e44d4f0eee08c0b626104eb7e60ab8de03463bc5da1773a2f69f1e6edec1648d648d65461d6520a7f3b0770 + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + checksum: 10/174741c667775680628a09117828bbeffb35ea543f59bf80649d0d60672f7815a0740ddece3cca87516199033a039166a6936434131fce2b6a820227e64f91ae languageName: node linkType: hard @@ -3387,45 +3387,6 @@ __metadata: languageName: node linkType: hard -"@backstage-community/plugin-puppetdb@npm:^0.6.0": - version: 0.6.0 - resolution: "@backstage-community/plugin-puppetdb@npm:0.6.0" - dependencies: - "@backstage/catalog-model": "npm:^1.7.3" - "@backstage/core-components": "npm:^0.17.1" - "@backstage/core-plugin-api": "npm:^1.10.6" - "@backstage/errors": "npm:^1.2.7" - "@backstage/plugin-catalog-react": "npm:^1.17.0" - "@material-ui/core": "npm:^4.12.2" - "@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0" - react-use: "npm:^17.2.4" - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 10/562b95a59ea7ecf829c60ee29a8c07eb111517d0d75f876050bbec5958e255b7478a4744dc4f2e899238c5c59d23b6c550095a210b936c385c71afc7e0950e7b - languageName: node - linkType: hard - -"@backstage-community/plugin-stackstorm@npm:^0.1.16": - version: 0.1.20 - resolution: "@backstage-community/plugin-stackstorm@npm:0.1.20" - dependencies: - "@backstage/core-components": "npm:^0.15.1" - "@backstage/core-plugin-api": "npm:^1.10.0" - "@backstage/errors": "npm:^1.2.4" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" - "@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0" - react-use: "npm:^17.2.4" - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 10/5dac0ca61198ba9e12ae06e9f00f5cf3cb2f620b58624e7270fa2539e0fb374f52bde9366cfa0f30dd123768a0a35d4515d2cbd822de92379ba59aaccedba869 - languageName: node - linkType: hard - "@backstage/app-defaults@workspace:^, @backstage/app-defaults@workspace:packages/app-defaults": version: 0.0.0-use.local resolution: "@backstage/app-defaults@workspace:packages/app-defaults" @@ -3789,45 +3750,12 @@ __metadata: languageName: unknown linkType: soft -"@backstage/canon@workspace:^, @backstage/canon@workspace:packages/canon": +"@backstage/canon@workspace:packages/canon": version: 0.0.0-use.local resolution: "@backstage/canon@workspace:packages/canon" dependencies: "@backstage/cli": "workspace:^" - "@base-ui-components/react": "npm:1.0.0-alpha.7" - "@remixicon/react": "npm:^4.6.0" - "@storybook/addon-essentials": "npm:^8.6.12" - "@storybook/addon-interactions": "npm:^8.6.12" - "@storybook/addon-styling-webpack": "npm:^1.0.1" - "@storybook/addon-themes": "npm:^8.6.12" - "@storybook/addon-webpack5-compiler-swc": "npm:^3.0.0" - "@storybook/blocks": "npm:^8.6.12" - "@storybook/react": "npm:^8.6.12" - "@storybook/react-webpack5": "npm:^8.6.12" - "@storybook/test": "npm:^8.6.12" - "@tanstack/react-table": "npm:^8.21.3" - "@types/react": "npm:^18.0.0" - "@types/react-dom": "npm:^18.0.0" - chalk: "npm:^5.4.1" - clsx: "npm:^2.1.1" - eslint-plugin-storybook: "npm:^0.12.0" - glob: "npm:^11.0.1" - globals: "npm:^15.11.0" - lightningcss: "npm:^1.29.1" - mini-css-extract-plugin: "npm:^2.9.2" - react: "npm:^18.0.2" - react-aria-components: "npm:^1.10.1" - react-dom: "npm:^18.0.2" - react-router-dom: "npm:^6.3.0" - storybook: "npm:^8.6.12" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true + "@backstage/ui": "workspace:^" languageName: unknown linkType: soft @@ -3844,7 +3772,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@npm:^1.4.3, @backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -4101,7 +4029,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@npm:^1.1.1, @backstage/config@npm:^1.2.0, @backstage/config@npm:^1.3.2, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@npm:^1.2.0, @backstage/config@npm:^1.3.2, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -4161,8 +4089,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/core-compat-api@workspace:packages/core-compat-api" dependencies: - "@backstage-community/plugin-puppetdb": "npm:^0.6.0" - "@backstage-community/plugin-stackstorm": "npm:^0.1.16" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" "@backstage/core-plugin-api": "workspace:^" @@ -4174,7 +4100,6 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" "@backstage/version-bridge": "workspace:^" - "@oriflame/backstage-plugin-score-card": "npm:^0.9.0" "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" "@types/react": "npm:^18.0.0" @@ -4194,110 +4119,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@npm:^0.13.10": - version: 0.13.10 - resolution: "@backstage/core-components@npm:0.13.10" - dependencies: - "@backstage/config": "npm:^1.1.1" - "@backstage/core-plugin-api": "npm:^1.8.2" - "@backstage/errors": "npm:^1.2.3" - "@backstage/theme": "npm:^0.5.0" - "@backstage/version-bridge": "npm:^1.0.7" - "@date-io/core": "npm:^1.3.13" - "@material-table/core": "npm:^3.1.0" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" - "@material-ui/lab": "npm:4.0.0-alpha.61" - "@react-hookz/web": "npm:^23.0.0" - "@types/react": "npm:^16.13.1 || ^17.0.0" - "@types/react-sparklines": "npm:^1.7.0" - "@types/react-text-truncate": "npm:^0.14.0" - ansi-regex: "npm:^6.0.1" - classnames: "npm:^2.2.6" - d3-selection: "npm:^3.0.0" - d3-shape: "npm:^3.0.0" - d3-zoom: "npm:^3.0.0" - dagre: "npm:^0.8.5" - linkify-react: "npm:4.1.3" - linkifyjs: "npm:4.1.3" - lodash: "npm:^4.17.21" - pluralize: "npm:^8.0.0" - qs: "npm:^6.9.4" - rc-progress: "npm:3.5.1" - react-helmet: "npm:6.1.0" - react-hook-form: "npm:^7.12.2" - react-idle-timer: "npm:5.6.2" - react-markdown: "npm:^8.0.0" - react-sparklines: "npm:^1.7.0" - react-syntax-highlighter: "npm:^15.4.5" - react-text-truncate: "npm:^0.19.0" - react-use: "npm:^17.3.2" - react-virtualized-auto-sizer: "npm:^1.0.11" - react-window: "npm:^1.8.6" - remark-gfm: "npm:^3.0.1" - zen-observable: "npm:^0.10.0" - zod: "npm:^3.22.4" - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 10/41231c51c52571da5a3ecb2b2fed41f05e537973fda7786a875b0978053a330f8224e6f211d3d4a6c4195d614834ae0886df6044c519659460eb8e4402fc6817 - languageName: node - linkType: hard - -"@backstage/core-components@npm:^0.15.1": - version: 0.15.1 - resolution: "@backstage/core-components@npm:0.15.1" - dependencies: - "@backstage/config": "npm:^1.2.0" - "@backstage/core-plugin-api": "npm:^1.10.0" - "@backstage/errors": "npm:^1.2.4" - "@backstage/theme": "npm:^0.6.0" - "@backstage/version-bridge": "npm:^1.0.10" - "@date-io/core": "npm:^1.3.13" - "@material-table/core": "npm:^3.1.0" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" - "@material-ui/lab": "npm:4.0.0-alpha.61" - "@react-hookz/web": "npm:^24.0.0" - "@types/react-sparklines": "npm:^1.7.0" - ansi-regex: "npm:^6.0.1" - classnames: "npm:^2.2.6" - d3-selection: "npm:^3.0.0" - d3-shape: "npm:^3.0.0" - d3-zoom: "npm:^3.0.0" - dagre: "npm:^0.8.5" - linkify-react: "npm:4.1.3" - linkifyjs: "npm:4.1.3" - lodash: "npm:^4.17.21" - pluralize: "npm:^8.0.0" - qs: "npm:^6.9.4" - rc-progress: "npm:3.5.1" - react-helmet: "npm:6.1.0" - react-hook-form: "npm:^7.12.2" - react-idle-timer: "npm:5.7.2" - react-markdown: "npm:^8.0.0" - react-sparklines: "npm:^1.7.0" - react-syntax-highlighter: "npm:^15.4.5" - react-use: "npm:^17.3.2" - react-virtualized-auto-sizer: "npm:^1.0.11" - react-window: "npm:^1.8.6" - remark-gfm: "npm:^3.0.1" - zen-observable: "npm:^0.10.0" - zod: "npm:^3.22.4" - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/48c765a7219255b4f230af13b6ba3e78cf0b23f1642a8175b6fa2498b7655dec662ea356f92fbbd9d834b55f8923540f879c0529a0bff0772ebff676152a2275 - languageName: node - linkType: hard - -"@backstage/core-components@npm:^0.17.1, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -4375,7 +4197,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@npm:^1.10.0, @backstage/core-plugin-api@npm:^1.10.6, @backstage/core-plugin-api@npm:^1.8.2, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -4486,7 +4308,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@npm:^1.2.3, @backstage/errors@npm:^1.2.4, @backstage/errors@npm:^1.2.7, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@npm:^1.2.4, @backstage/errors@npm:^1.2.7, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4686,7 +4508,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.24, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -4717,7 +4539,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@npm:^1.15.0, @backstage/integration@npm:^1.9.0, @backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": +"@backstage/integration@npm:^1.15.0, @backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" dependencies: @@ -5897,7 +5719,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@npm:^1.0.20, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -6023,7 +5845,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.17.0, @backstage/plugin-catalog-react@npm:^1.9.3, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -7613,6 +7435,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" "@backstage/types": "workspace:^" "@isomorphic-git/pgp-plugin": "npm:^0.0.7" @@ -8113,6 +7936,7 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" + "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -8589,23 +8413,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@npm:^0.5.0": - version: 0.5.7 - resolution: "@backstage/theme@npm:0.5.7" - dependencies: - "@emotion/react": "npm:^11.10.5" - "@emotion/styled": "npm:^11.10.5" - "@mui/material": "npm:^5.12.2" - peerDependencies: - "@material-ui/core": ^4.12.2 - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - checksum: 10/b826aabc3f483e7f0dd2285c1510c4a59797433a2884a2423b22bfce6627aefabcd258aac23edecb58edb8275a87deb4ef212646d1832721a56862d46d8b4001 - languageName: node - linkType: hard - -"@backstage/theme@npm:^0.6.0, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -8643,7 +8451,49 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@npm:^1.0.10, @backstage/version-bridge@npm:^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/ui@workspace:^, @backstage/ui@workspace:packages/ui": + version: 0.0.0-use.local + resolution: "@backstage/ui@workspace:packages/ui" + dependencies: + "@backstage/cli": "workspace:^" + "@base-ui-components/react": "npm:1.0.0-alpha.7" + "@remixicon/react": "npm:^4.6.0" + "@storybook/addon-essentials": "npm:^8.6.12" + "@storybook/addon-interactions": "npm:^8.6.12" + "@storybook/addon-styling-webpack": "npm:^1.0.1" + "@storybook/addon-webpack5-compiler-swc": "npm:^3.0.0" + "@storybook/blocks": "npm:^8.6.12" + "@storybook/react": "npm:^8.6.12" + "@storybook/react-webpack5": "npm:^8.6.12" + "@storybook/test": "npm:^8.6.12" + "@tanstack/react-table": "npm:^8.21.3" + "@types/react": "npm:^18.0.0" + "@types/react-dom": "npm:^18.0.0" + chalk: "npm:^5.4.1" + clsx: "npm:^2.1.1" + eslint-plugin-storybook: "npm:^0.12.0" + glob: "npm:^11.0.1" + globals: "npm:^15.11.0" + lightningcss: "npm:^1.29.1" + mini-css-extract-plugin: "npm:^2.9.2" + motion: "npm:^12.20.1" + react: "npm:^18.0.2" + react-aria-components: "npm:^1.10.1" + react-dom: "npm:^18.0.2" + react-router-dom: "npm:^6.3.0" + storybook: "npm:^8.6.12" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + languageName: unknown + linkType: soft + +"@backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: @@ -9149,6 +8999,16 @@ __metadata: languageName: node linkType: hard +"@dependents/detective-less@npm:^5.0.1": + version: 5.0.1 + resolution: "@dependents/detective-less@npm:5.0.1" + dependencies: + gonzales-pe: "npm:^4.3.0" + node-source-walk: "npm:^7.0.1" + checksum: 10/647d4427f6aad119bdfea607ab19ca30be827f7f0462677b5a538d8f8ab4ebda2c05ece60fceb5d3abb093e69ab3393e24a8e966936d2745b07421cfd014b14f + languageName: node + linkType: hard + "@elastic/elasticsearch-mock@npm:^1.0.0": version: 1.0.0 resolution: "@elastic/elasticsearch-mock@npm:1.0.0" @@ -9878,16 +9738,16 @@ __metadata: languageName: node linkType: hard -"@gerrit0/mini-shiki@npm:^3.2.2": - version: 3.4.0 - resolution: "@gerrit0/mini-shiki@npm:3.4.0" +"@gerrit0/mini-shiki@npm:^3.7.0": + version: 3.7.0 + resolution: "@gerrit0/mini-shiki@npm:3.7.0" dependencies: - "@shikijs/engine-oniguruma": "npm:^3.4.0" - "@shikijs/langs": "npm:^3.4.0" - "@shikijs/themes": "npm:^3.4.0" - "@shikijs/types": "npm:^3.4.0" + "@shikijs/engine-oniguruma": "npm:^3.7.0" + "@shikijs/langs": "npm:^3.7.0" + "@shikijs/themes": "npm:^3.7.0" + "@shikijs/types": "npm:^3.7.0" "@shikijs/vscode-textmate": "npm:^10.0.2" - checksum: 10/2e116b8a6cb4d63db0fc8d96ba696befb4b4d66d4eaf4673c2585e798ae871e7e7cc581252cdc08169e5c19ae1aa496d93286da7626a36f7b0d298c660178855 + checksum: 10/d9af211439551e2198309b6b3a274174ef7f84ab74d55872a6ab0302fe5b41a2000eaad65574ef5cd8fedad13d5a099e64863d489a991df7a3efd8e3250f8912 languageName: node linkType: hard @@ -9958,14 +9818,14 @@ __metadata: linkType: hard "@google-cloud/cloud-sql-connector@npm:^1.4.0": - version: 1.8.1 - resolution: "@google-cloud/cloud-sql-connector@npm:1.8.1" + version: 1.8.2 + resolution: "@google-cloud/cloud-sql-connector@npm:1.8.2" dependencies: - "@googleapis/sqladmin": "npm:^29.0.0" - gaxios: "npm:^6.1.1" - google-auth-library: "npm:^9.2.0" + "@googleapis/sqladmin": "npm:^31.0.0" + gaxios: "npm:^7.0.0" + google-auth-library: "npm:^10.0.0" p-throttle: "npm:^7.0.0" - checksum: 10/e13e2e47993d74c770c73318a73047b017266f6f8102e26ebcf90c484fd78ba6141b0fc60f4eced55d438150655b8514423c19e3f30da73a1aaf1c77baadd0ab + checksum: 10/a9e8113f6b252e93ebdac2901c47584fa2c50d4ff0ad7ce1e1beb8ac8c710b24543927b2231eeb0f74eb467e122ec313ba3fb845d6f5878d35760eb3021aa6ec languageName: node linkType: hard @@ -10067,12 +9927,12 @@ __metadata: languageName: node linkType: hard -"@googleapis/sqladmin@npm:^29.0.0": - version: 29.0.0 - resolution: "@googleapis/sqladmin@npm:29.0.0" +"@googleapis/sqladmin@npm:^31.0.0": + version: 31.1.0 + resolution: "@googleapis/sqladmin@npm:31.1.0" dependencies: - googleapis-common: "npm:^7.0.0" - checksum: 10/3bf9eea2e6333d394da88404172aeed5ee5fca5fe2ebbba84d427990aab0083281a4cb948c023817ae6dbb618a1e43a296176c7703badd66a60bde695d7c5b3f + googleapis-common: "npm:^8.0.2-rc.0" + checksum: 10/720365e99bff8b7de161dc629ffb097624b98a3ff42febca47d9a9c73480b66faff39f3601614dce3178b3acf9d49c6e006633e1847cceaa7d21bc8437fa1936 languageName: node linkType: hard @@ -11506,7 +11366,7 @@ __metadata: languageName: node linkType: hard -"@material-ui/icons@npm:^4.11.2, @material-ui/icons@npm:^4.11.3, @material-ui/icons@npm:^4.9.1": +"@material-ui/icons@npm:^4.11.3, @material-ui/icons@npm:^4.9.1": version: 4.11.3 resolution: "@material-ui/icons@npm:4.11.3" dependencies: @@ -12343,11 +12203,11 @@ __metadata: languageName: node linkType: hard -"@nestjs/common@npm:11.1.1": - version: 11.1.1 - resolution: "@nestjs/common@npm:11.1.1" +"@nestjs/common@npm:11.1.3": + version: 11.1.3 + resolution: "@nestjs/common@npm:11.1.3" dependencies: - file-type: "npm:20.5.0" + file-type: "npm:21.0.0" iterare: "npm:1.2.1" load-esm: "npm:1.0.2" tslib: "npm:2.8.1" @@ -12362,13 +12222,13 @@ __metadata: optional: true class-validator: optional: true - checksum: 10/b58b951984df667b794a6c9cf65dda8ee43fe0c4e552183e045b126c82d99b50cddb1e84ea03b8dd7b04fca512acb107222ffad6b19dba359323f9b813032161 + checksum: 10/b1c9699cdf9cee96ed0178e5eed3b1829c210bbdbd703bb9e1e0def2c7456273d73329635439b16164e43de8a8d54dd5b7d1dd5dba65417d746bd731b8c5d685 languageName: node linkType: hard -"@nestjs/core@npm:11.1.1": - version: 11.1.1 - resolution: "@nestjs/core@npm:11.1.1" +"@nestjs/core@npm:11.1.3": + version: 11.1.3 + resolution: "@nestjs/core@npm:11.1.3" dependencies: "@nuxt/opencollective": "npm:0.4.1" fast-safe-stringify: "npm:2.1.1" @@ -12390,7 +12250,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 10/88f8a3c52a98c059e6d93c5faf9194daee4667b1a855f88233582acf51e3be9aedb3e3f7f992da46e0e45df31ad4e045e0296e6e35ea14e2245d4069176711c0 + checksum: 10/b46a9f877170f7e96429da5970684525277bcb341f3a24032b6748ad503b5c7164b77410daf9c0f3ca99b5f6b99985d5eb739501cfc01c941218397f32f2d095 languageName: node linkType: hard @@ -13455,12 +13315,12 @@ __metadata: linkType: hard "@openapitools/openapi-generator-cli@npm:^2.4.26, @openapitools/openapi-generator-cli@npm:^2.7.0": - version: 2.20.2 - resolution: "@openapitools/openapi-generator-cli@npm:2.20.2" + version: 2.20.5 + resolution: "@openapitools/openapi-generator-cli@npm:2.20.5" dependencies: "@nestjs/axios": "npm:4.0.0" - "@nestjs/common": "npm:11.1.1" - "@nestjs/core": "npm:11.1.1" + "@nestjs/common": "npm:11.1.3" + "@nestjs/core": "npm:11.1.3" "@nuxtjs/opencollective": "npm:0.3.2" axios: "npm:1.9.0" chalk: "npm:4.1.2" @@ -13469,7 +13329,7 @@ __metadata: concurrently: "npm:6.5.1" console.table: "npm:0.10.0" fs-extra: "npm:11.3.0" - glob: "npm:9.3.5" + glob: "npm:11.0.3" inquirer: "npm:8.2.6" lodash: "npm:4.17.21" proxy-agent: "npm:6.5.0" @@ -13478,7 +13338,7 @@ __metadata: tslib: "npm:2.8.1" bin: openapi-generator-cli: main.js - checksum: 10/29807b52555e7307207eff6e0c4c1a25b970252915e13d847a6c275d1d638af0732761e51816f5bb5a91830ebabc044b3924a106db8cffa19dda01517a77be17 + checksum: 10/76e40b238074c8bf09c99c70222cd80aa1d8be8b9abe6c400542f1bd46c3058238247085835a08a57bb0a43dceeff40b3cb8c4ea736692d040c1d29c48bd1db7 languageName: node linkType: hard @@ -13496,6 +13356,15 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/api-logs@npm:0.202.0, @opentelemetry/api-logs@npm:^0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/api-logs@npm:0.202.0" + dependencies: + "@opentelemetry/api": "npm:^1.3.0" + checksum: 10/22171137ad1d876a79a6f046b4adcc44a13941a07f2172948e4c8dbb6cacfe276b1fa5087f15e4acdd567f748010d531321c93ebf93a6c09586351c9048bf6c7 + languageName: node + linkType: hard + "@opentelemetry/api-logs@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/api-logs@npm:0.54.2" @@ -13505,15 +13374,6 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api-logs@npm:0.56.0, @opentelemetry/api-logs@npm:^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/api-logs@npm:0.56.0" - dependencies: - "@opentelemetry/api": "npm:^1.3.0" - checksum: 10/5a6e25015acada7449d11124e9adbbe6670e1e9f7e8b46c60360ac89bb1537f2be326bcf18c66dcbcdee9f34e3a18bd4807c5a40faa0a4ac0135cb3675efb2a9 - languageName: node - linkType: hard - "@opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.4.0, @opentelemetry/api@npm:^1.9.0, @opentelemetry/api@npm:~1.9.0": version: 1.9.0 resolution: "@opentelemetry/api@npm:1.9.0" @@ -13521,60 +13381,62 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/auto-instrumentations-node@npm:^0.54.0": - version: 0.54.0 - resolution: "@opentelemetry/auto-instrumentations-node@npm:0.54.0" +"@opentelemetry/auto-instrumentations-node@npm:^0.61.0": + version: 0.61.0 + resolution: "@opentelemetry/auto-instrumentations-node@npm:0.61.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/instrumentation-amqplib": "npm:^0.45.0" - "@opentelemetry/instrumentation-aws-lambda": "npm:^0.49.0" - "@opentelemetry/instrumentation-aws-sdk": "npm:^0.48.0" - "@opentelemetry/instrumentation-bunyan": "npm:^0.44.0" - "@opentelemetry/instrumentation-cassandra-driver": "npm:^0.44.0" - "@opentelemetry/instrumentation-connect": "npm:^0.42.0" - "@opentelemetry/instrumentation-cucumber": "npm:^0.12.0" - "@opentelemetry/instrumentation-dataloader": "npm:^0.15.0" - "@opentelemetry/instrumentation-dns": "npm:^0.42.0" - "@opentelemetry/instrumentation-express": "npm:^0.46.0" - "@opentelemetry/instrumentation-fastify": "npm:^0.43.0" - "@opentelemetry/instrumentation-fs": "npm:^0.18.0" - "@opentelemetry/instrumentation-generic-pool": "npm:^0.42.0" - "@opentelemetry/instrumentation-graphql": "npm:^0.46.0" - "@opentelemetry/instrumentation-grpc": "npm:^0.56.0" - "@opentelemetry/instrumentation-hapi": "npm:^0.44.0" - "@opentelemetry/instrumentation-http": "npm:^0.56.0" - "@opentelemetry/instrumentation-ioredis": "npm:^0.46.0" - "@opentelemetry/instrumentation-kafkajs": "npm:^0.6.0" - "@opentelemetry/instrumentation-knex": "npm:^0.43.0" - "@opentelemetry/instrumentation-koa": "npm:^0.46.0" - "@opentelemetry/instrumentation-lru-memoizer": "npm:^0.43.0" - "@opentelemetry/instrumentation-memcached": "npm:^0.42.0" - "@opentelemetry/instrumentation-mongodb": "npm:^0.50.0" - "@opentelemetry/instrumentation-mongoose": "npm:^0.45.0" - "@opentelemetry/instrumentation-mysql": "npm:^0.44.0" - "@opentelemetry/instrumentation-mysql2": "npm:^0.44.0" - "@opentelemetry/instrumentation-nestjs-core": "npm:^0.43.0" - "@opentelemetry/instrumentation-net": "npm:^0.42.0" - "@opentelemetry/instrumentation-pg": "npm:^0.49.0" - "@opentelemetry/instrumentation-pino": "npm:^0.45.0" - "@opentelemetry/instrumentation-redis": "npm:^0.45.0" - "@opentelemetry/instrumentation-redis-4": "npm:^0.45.0" - "@opentelemetry/instrumentation-restify": "npm:^0.44.0" - "@opentelemetry/instrumentation-router": "npm:^0.43.0" - "@opentelemetry/instrumentation-socket.io": "npm:^0.45.0" - "@opentelemetry/instrumentation-tedious": "npm:^0.17.0" - "@opentelemetry/instrumentation-undici": "npm:^0.9.0" - "@opentelemetry/instrumentation-winston": "npm:^0.43.0" - "@opentelemetry/resource-detector-alibaba-cloud": "npm:^0.29.6" - "@opentelemetry/resource-detector-aws": "npm:^1.9.0" - "@opentelemetry/resource-detector-azure": "npm:^0.4.0" - "@opentelemetry/resource-detector-container": "npm:^0.5.2" - "@opentelemetry/resource-detector-gcp": "npm:^0.31.0" - "@opentelemetry/resources": "npm:^1.24.0" - "@opentelemetry/sdk-node": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/instrumentation-amqplib": "npm:^0.49.0" + "@opentelemetry/instrumentation-aws-lambda": "npm:^0.53.1" + "@opentelemetry/instrumentation-aws-sdk": "npm:^0.55.0" + "@opentelemetry/instrumentation-bunyan": "npm:^0.48.0" + "@opentelemetry/instrumentation-cassandra-driver": "npm:^0.48.0" + "@opentelemetry/instrumentation-connect": "npm:^0.46.0" + "@opentelemetry/instrumentation-cucumber": "npm:^0.17.1" + "@opentelemetry/instrumentation-dataloader": "npm:^0.20.0" + "@opentelemetry/instrumentation-dns": "npm:^0.46.0" + "@opentelemetry/instrumentation-express": "npm:^0.51.1" + "@opentelemetry/instrumentation-fastify": "npm:^0.47.1" + "@opentelemetry/instrumentation-fs": "npm:^0.22.0" + "@opentelemetry/instrumentation-generic-pool": "npm:^0.46.1" + "@opentelemetry/instrumentation-graphql": "npm:^0.50.0" + "@opentelemetry/instrumentation-grpc": "npm:^0.202.0" + "@opentelemetry/instrumentation-hapi": "npm:^0.49.0" + "@opentelemetry/instrumentation-http": "npm:^0.202.0" + "@opentelemetry/instrumentation-ioredis": "npm:^0.50.1" + "@opentelemetry/instrumentation-kafkajs": "npm:^0.11.0" + "@opentelemetry/instrumentation-knex": "npm:^0.47.0" + "@opentelemetry/instrumentation-koa": "npm:^0.50.2" + "@opentelemetry/instrumentation-lru-memoizer": "npm:^0.47.0" + "@opentelemetry/instrumentation-memcached": "npm:^0.46.0" + "@opentelemetry/instrumentation-mongodb": "npm:^0.55.1" + "@opentelemetry/instrumentation-mongoose": "npm:^0.49.0" + "@opentelemetry/instrumentation-mysql": "npm:^0.48.1" + "@opentelemetry/instrumentation-mysql2": "npm:^0.48.1" + "@opentelemetry/instrumentation-nestjs-core": "npm:^0.48.1" + "@opentelemetry/instrumentation-net": "npm:^0.46.1" + "@opentelemetry/instrumentation-oracledb": "npm:^0.28.0" + "@opentelemetry/instrumentation-pg": "npm:^0.54.1" + "@opentelemetry/instrumentation-pino": "npm:^0.49.1" + "@opentelemetry/instrumentation-redis": "npm:^0.50.0" + "@opentelemetry/instrumentation-restify": "npm:^0.48.2" + "@opentelemetry/instrumentation-router": "npm:^0.47.0" + "@opentelemetry/instrumentation-runtime-node": "npm:^0.16.0" + "@opentelemetry/instrumentation-socket.io": "npm:^0.49.0" + "@opentelemetry/instrumentation-tedious": "npm:^0.21.1" + "@opentelemetry/instrumentation-undici": "npm:^0.13.2" + "@opentelemetry/instrumentation-winston": "npm:^0.47.0" + "@opentelemetry/resource-detector-alibaba-cloud": "npm:^0.31.2" + "@opentelemetry/resource-detector-aws": "npm:^2.2.0" + "@opentelemetry/resource-detector-azure": "npm:^0.9.0" + "@opentelemetry/resource-detector-container": "npm:^0.7.2" + "@opentelemetry/resource-detector-gcp": "npm:^0.36.0" + "@opentelemetry/resources": "npm:^2.0.0" + "@opentelemetry/sdk-node": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.4.1 - checksum: 10/0b5992c0ab3eeb22a81ffcd8f4f1b9c4694e0c2fa5e208918774119838f20921e7918e39f801fb1194bf8ceca5e58d87c82f153ab1e26d7bd502a7644b125330 + "@opentelemetry/core": ^2.0.0 + checksum: 10/845728e050aa40f501ca3c67ad10ef64859413cb3af6926c6e64dbec206dc4ee7c8cff4d93df95345cebf8970427a03665032f97941a6a1153699f0fbbac1a6f languageName: node linkType: hard @@ -13587,12 +13449,12 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/context-async-hooks@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/context-async-hooks@npm:1.29.0" +"@opentelemetry/context-async-hooks@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/context-async-hooks@npm:2.0.1" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/bfd960bd03d8c5b2d92447fd7435b86ff919299b56821fe8f99f2ffe19831f0ecadba25bd52a37faff0f98c4fecdcc76e6886e56a3844b367360c6232674ae0e + checksum: 10/198dacdce36377f6ded7062eb9fc77f86c9fcc8c86dd395e9cb276e14a01c7906ea2f0271999cae21bf251dbec44641286b8bd34a39c67c88c08ed925a986f4b languageName: node linkType: hard @@ -13607,18 +13469,18 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/core@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/core@npm:1.29.0" +"@opentelemetry/core@npm:2.0.1, @opentelemetry/core@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/core@npm:2.0.1" dependencies: - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/eb62dce11cb0cb637acfb3582ad25e48766d9fb37b6b70e57f3c60521c7680a85431a0853c50d98cc8e807e5e3c2fddda314623d879e932bf1a5f629344b39ce + checksum: 10/dd891afd427067a9e6c610c36ab5638b0b9e5303ccca7c75ad744f5db53c6162a4b5d9cd2f5a77cdc3e4bda2eae850a4e29983ea244c929b7b872b7e086fc61c languageName: node linkType: hard -"@opentelemetry/core@npm:1.30.1, @opentelemetry/core@npm:^1.0.0, @opentelemetry/core@npm:^1.1.0, @opentelemetry/core@npm:^1.25.0, @opentelemetry/core@npm:^1.25.1, @opentelemetry/core@npm:^1.26.0, @opentelemetry/core@npm:^1.29.0, @opentelemetry/core@npm:^1.8.0": +"@opentelemetry/core@npm:^1.29.0": version: 1.30.1 resolution: "@opentelemetry/core@npm:1.30.1" dependencies: @@ -13629,6 +13491,22 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-logs-otlp-grpc@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-logs-otlp-grpc@npm:0.202.0" + dependencies: + "@grpc/grpc-js": "npm:^1.7.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-grpc-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/sdk-logs": "npm:0.202.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/b293a3778b6d5b1fe07b9203fe83d0dde3ea57e48efec8d4ccfc27d007fdb5cdafe7446ff10ea3eca69eb2fba8bdb97546a7dfcfc21b73d303e94e15f917b253 + languageName: node + linkType: hard + "@opentelemetry/exporter-logs-otlp-grpc@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-logs-otlp-grpc@npm:0.54.2" @@ -13644,18 +13522,18 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-logs-otlp-grpc@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-logs-otlp-grpc@npm:0.56.0" +"@opentelemetry/exporter-logs-otlp-http@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-logs-otlp-http@npm:0.202.0" dependencies: - "@grpc/grpc-js": "npm:^1.7.1" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-grpc-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/sdk-logs": "npm:0.56.0" + "@opentelemetry/api-logs": "npm:0.202.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/sdk-logs": "npm:0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/e798faebab931c25941d7d6ebac91dbc0f0fd86b9a6ec641b12ba76ce4675a68acd4d7099ef41d5c040650b0ee2881c61f5cab053dcd280f3cb6dcc29fc450d5 + checksum: 10/850be5f7a2b0468887357845ffb7f8ca53dfedcd8fc79fbd4d8825cabbdc9a27be107e7aecb6b21ba544cead796e13f116396fcc66ba58954e47ac8fc1eaf270 languageName: node linkType: hard @@ -13674,18 +13552,20 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-logs-otlp-http@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-logs-otlp-http@npm:0.56.0" +"@opentelemetry/exporter-logs-otlp-proto@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-logs-otlp-proto@npm:0.202.0" dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/sdk-logs": "npm:0.56.0" + "@opentelemetry/api-logs": "npm:0.202.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-logs": "npm:0.202.0" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/f2313074b0b124a36c292a9f97d6865df4c8d97ff2c4f95a122212c32a7ab91f0a4b6c1e01c2d1fe8c6619d245be81c7d7ab5178ddf2b8cfec15b224ae38c9e5 + checksum: 10/b69e19a035ae7d2d3f99f5ef40760e9f874685de9679b09a143ae9c120a248d9b5995eeec869ebeed6df1a4ebb4e312b5a569f4189410ad02e6ec4438f8fd63f languageName: node linkType: hard @@ -13706,20 +13586,65 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-logs-otlp-proto@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-logs-otlp-proto@npm:0.56.0" +"@opentelemetry/exporter-metrics-otlp-grpc@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-metrics-otlp-grpc@npm:0.202.0" dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-logs": "npm:0.56.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" + "@grpc/grpc-js": "npm:^1.7.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/exporter-metrics-otlp-http": "npm:0.202.0" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-grpc-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-metrics": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/3d062bd054108a0d40da1295ea11f68d4b71f9cf665bde479498939680497a54e1d542f358bc9b04b3332da15c95b1bdb570f7b60ca1a96909a2675d9f26a1ae + checksum: 10/383e6eee1016dbdfe78ed8c96fb6e8e314e0103a11353373f794637594b2b935efc5707eee33712a4ed242b12c808a09584105db1b2e2deab477d80e3d2d06ed + languageName: node + linkType: hard + +"@opentelemetry/exporter-metrics-otlp-http@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-metrics-otlp-http@npm:0.202.0" + dependencies: + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-metrics": "npm:2.0.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/ed694b8369bb2f979f0aa3552716b267060e5d8d7853fd645e0ae776888091a08c079e9f1e88d8f7eb93d9fe31f0fbb887ebb9469177c2ec2af16c247f8faf5d + languageName: node + linkType: hard + +"@opentelemetry/exporter-metrics-otlp-proto@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-metrics-otlp-proto@npm:0.202.0" + dependencies: + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/exporter-metrics-otlp-http": "npm:0.202.0" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-metrics": "npm:2.0.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/22ecc54c4a19a36d5f6ba8cc061e25fba6ff9f2bbaff9a84f8c1e7e5253b2b0dc07ac18e21884eafcb31e6693ce59912baeb19c722a07ad4da9f22e2a6f94549 + languageName: node + linkType: hard + +"@opentelemetry/exporter-prometheus@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-prometheus@npm:0.202.0" + dependencies: + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-metrics": "npm:2.0.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/e6cf4dfdc3bd6ccd402a00e0cb1bd2fa5cc4c813a86b23d27bf851e38a22788dac234c10d643a1506acf10415b1cba9bd68da7554358ba32a0ad8b978bc2d467 languageName: node linkType: hard @@ -13736,6 +13661,23 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-trace-otlp-grpc@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-trace-otlp-grpc@npm:0.202.0" + dependencies: + "@grpc/grpc-js": "npm:^1.7.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-grpc-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/28cd0d2a0d3ef08cd7830b044690c5e6d86eb36f0d1298d9cd921f89c382cfbd3f80272c9fb8c12ece7eb417a48f852f6b3c299c21b0eba5d340d244cd41e6e2 + languageName: node + linkType: hard + "@opentelemetry/exporter-trace-otlp-grpc@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-trace-otlp-grpc@npm:0.54.2" @@ -13752,19 +13694,18 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-trace-otlp-grpc@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-trace-otlp-grpc@npm:0.56.0" +"@opentelemetry/exporter-trace-otlp-http@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.202.0" dependencies: - "@grpc/grpc-js": "npm:^1.7.1" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-grpc-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/3092a8c1ae7e092904b135760c7512636e132fc53c1657e5c9beda50ed104cfb0e85fed0fe53c53d95afd6b9403f6a9767106dd581ed5ae4559120c7d0616faa + checksum: 10/f9e60e51b5dcca3d4d32f2091f04faa2bcaf677b9f8a88990c8cdc7c6345e4244e46c4e8df1c336fc6f741aea092407032ade1236089eb729196e6fcdc055ad0 languageName: node linkType: hard @@ -13783,18 +13724,18 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-trace-otlp-http@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.56.0" +"@opentelemetry/exporter-trace-otlp-proto@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/exporter-trace-otlp-proto@npm:0.202.0" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/2c9a0fb15ace10ca904c27a06d84b2a60b38ae989d045c3c8466419a5439d3dd5d0584481036ee1675cbf8eb403b863c7d51a086c10ffb5435235375062b33af + checksum: 10/884d1d097f3defee57dbb64281815a062603f64ce81e2f4460477925f4fb23c1d42aac2bb9d3b188e00cacaa9d231ef11e2e0f36e4b26863d009e795953191d8 languageName: node linkType: hard @@ -13813,21 +13754,6 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-trace-otlp-proto@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/exporter-trace-otlp-proto@npm:0.56.0" - dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/85197740a1744a16f10ee355e250c4e7a77250454266cf9bad1875beb245dd39ba4fb19e87322fae65bf038075698fa5d1b284cc7d76160ee6eff279b728bef3 - languageName: node - linkType: hard - "@opentelemetry/exporter-zipkin@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/exporter-zipkin@npm:1.27.0" @@ -13842,508 +13768,531 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/exporter-zipkin@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/exporter-zipkin@npm:1.29.0" +"@opentelemetry/exporter-zipkin@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/exporter-zipkin@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/8fdd2873723c48a00b9e82bfc4d878887cb65f68b7843d32e402677758481ce523759f30aa800bd538441dcca85a83765f0b4ae720d1309dbdce0c858fc93ec4 + checksum: 10/67fa9c4e33276218fd8a4c6fb04bab55aaf35383e396056034ab1f826f3d00c672b91ec890a9859df13c9f2890d3dc3d9f1a2b2904f0855272fc0cb48157e874 languageName: node linkType: hard -"@opentelemetry/instrumentation-amqplib@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-amqplib@npm:0.45.0" - dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/7a0be9861a12a7baf1a63fecd4eb221eecb9cb422223d1b62f183b14c1999e9ba039450a60bbaad139abab040d48dc843d4c93e8247b39215e31066e4ff9aa17 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-aws-lambda@npm:^0.49.0": +"@opentelemetry/instrumentation-amqplib@npm:^0.49.0": version: 0.49.0 - resolution: "@opentelemetry/instrumentation-aws-lambda@npm:0.49.0" + resolution: "@opentelemetry/instrumentation-amqplib@npm:0.49.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@types/aws-lambda": "npm:8.10.143" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/efd4d8e66fd0cb418b923bf971a0bae607b06dc02bd7a0215a316013fd8bf4e2d80d7c099215b34cf4466115664fa062c9395816e4456b468314cff7ab24125e + checksum: 10/891f201f476d77b960b6f3dc0186b3af52f7c249b69da365da184b01cf2056052fa93f85196e8811156908b2f532adf6a13773f102b4a78626046275827df2b1 languageName: node linkType: hard -"@opentelemetry/instrumentation-aws-sdk@npm:^0.48.0": +"@opentelemetry/instrumentation-aws-lambda@npm:^0.53.1": + version: 0.53.1 + resolution: "@opentelemetry/instrumentation-aws-lambda@npm:0.53.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/aws-lambda": "npm:8.10.150" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/a305988e8332e416c5fd81ffbdad71ffd68eeb623c55ea26fa25212f3c0c254ce30022461067981e4a7c5cfb1e25d1f1ed306d09f09d68c17fbbe693ec2ed4a1 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-aws-sdk@npm:^0.55.0": + version: 0.55.0 + resolution: "@opentelemetry/instrumentation-aws-sdk@npm:0.55.0" + dependencies: + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/propagation-utils": "npm:^0.31.2" + "@opentelemetry/semantic-conventions": "npm:^1.34.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/c2ce4063f4761baa6e12d1830270952d67d9bd0fdba3d15b97ec107df54d2a21c01be6960e0c2e3dcb2358bc57ba977b694e02c78a01c0f193377d0e4557dd7e + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-bunyan@npm:^0.48.0": version: 0.48.0 - resolution: "@opentelemetry/instrumentation-aws-sdk@npm:0.48.0" + resolution: "@opentelemetry/instrumentation-bunyan@npm:0.48.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/propagation-utils": "npm:^0.30.14" + "@opentelemetry/api-logs": "npm:^0.202.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@types/bunyan": "npm:1.8.11" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/c0147693e5e6202198448b0ca8b2550ca972d9a72a78b3c95edb1942b6e0a1b295351c205dbfc7562e11a50b815a64b3b920ceb474d6a59daa4cfbea01d8f621 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-cassandra-driver@npm:^0.48.0": + version: 0.48.0 + resolution: "@opentelemetry/instrumentation-cassandra-driver@npm:0.48.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/7d036e6467dbbaed5f3569ead30f628e73c6144c769278dec29eb9ef85804dda48c37a864c05ce0fcf69f89ea7447999e0630db612c361e72980fbe7e6615d39 + checksum: 10/7a3b2ba1b472108f0b1e1e799d7f8f8d0eb10034378b4b06fbec0e1fc59e095f3e374dd7739047856d27f00d8706603db08cfb90aa37b427fce18b43b0731932 languageName: node linkType: hard -"@opentelemetry/instrumentation-bunyan@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-bunyan@npm:0.44.0" +"@opentelemetry/instrumentation-connect@npm:^0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-connect@npm:0.46.0" dependencies: - "@opentelemetry/api-logs": "npm:^0.56.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@types/bunyan": "npm:1.8.9" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/2be4fd8ec960bfd355626c31e7f0192a3dcd232d5749eb7fe46adfd1f33298e55bab595dd9b45a2569a4c712c6d6dc6b4aea8374bc3fe248da9d2bf9d0e0bc3b - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-cassandra-driver@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-cassandra-driver@npm:0.44.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/connect": "npm:3.4.38" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/7617d2097710e94389c00fbf82e1e49f6b772370b2746fd6744681b46a2b3f4bbfa909bfcd556dc0eb99ad3d095c78f1d3016abff532b782d95164339213b3d0 + checksum: 10/e5b96bde0b8fbcf2edc22ed3a5ac655758440e9a3f8c4f39ae3dcf88edda8be6dd0bb121b3cffcf8df8b53fb0aef3c5bc62549cf5c24439fb9ba15a03f93280c languageName: node linkType: hard -"@opentelemetry/instrumentation-connect@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-connect@npm:0.42.0" +"@opentelemetry/instrumentation-cucumber@npm:^0.17.1": + version: 0.17.1 + resolution: "@opentelemetry/instrumentation-cucumber@npm:0.17.1" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@types/connect": "npm:3.4.36" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/f03090f36028d654fcbb649d52ec57613b407aceb7e3d61978ab4f737c3617f4dd7061612139e0cb856a9df566d1ff0202f2c426ee3dacaf2a68c1ea5a34be63 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-cucumber@npm:^0.12.0": - version: 0.12.0 - resolution: "@opentelemetry/instrumentation-cucumber@npm:0.12.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/0829bd8f609fc038e1649e1f214f63398304e8479ee600706c072f54b58a6e9bed5d59af3d13d62da629ecf78b1c59d2217fff4b472a062b1967b7142130e33b + checksum: 10/ef65ef03f4aa79a3b4ae223aebf714b62b7d96261680932df02ba4590685253d4e7bf44ac58109e39a951bb0217ffef11f12224ede62ce65ac93a46f2b65e517 languageName: node linkType: hard -"@opentelemetry/instrumentation-dataloader@npm:^0.15.0": - version: 0.15.0 - resolution: "@opentelemetry/instrumentation-dataloader@npm:0.15.0" +"@opentelemetry/instrumentation-dataloader@npm:^0.20.0": + version: 0.20.0 + resolution: "@opentelemetry/instrumentation-dataloader@npm:0.20.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/2a13e5159f5977f8d14955d6ce6994a6c6249ae25da10975aca782d0a74d74355143cdc4c47c99f36abd71d6097b610aa34611bb64a5d042948bbb788c26dd77 + checksum: 10/4d9e5600644e5d941860d492be9bd1b3966acd69e281f491f151347d482464e1481f7ce8c6898e744e235d052c16868774b6353d606a58a3538b9e32d43c2b92 languageName: node linkType: hard -"@opentelemetry/instrumentation-dns@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-dns@npm:0.42.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/5bbdb5095f257c479a11eabaf49019e8ed5d49ececbeba9c5723ecc9f3343f601edecbea36d9a7581e46dcd80cb27fe7299fea1e42cd60083a1f50b3df32c1a0 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-express@npm:^0.46.0": +"@opentelemetry/instrumentation-dns@npm:^0.46.0": version: 0.46.0 - resolution: "@opentelemetry/instrumentation-express@npm:0.46.0" + resolution: "@opentelemetry/instrumentation-dns@npm:0.46.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/68c72e76a5c53d7d49632fb0126c097aa717c173fc0a2502f4b03be382844fbcdcc385f49dab502853006e3e64555879e5c26a24d126a87d7825ad01be1a9f01 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-express@npm:^0.51.1": + version: 0.51.1 + resolution: "@opentelemetry/instrumentation-express@npm:0.51.1" + dependencies: + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/757b074aece5ad34ac082c54f3c4a6aadcbdf6cfb55510de5d77acc3e75e28a3c7f8b80ba5727b5d47ffa70790d0fdc672fc67d5f3854ba2acbb011424ce914c + checksum: 10/a0ecb32a8599d826a032df0c5558d43bf5024b131b93e6e57c659f208e265d40bafbad15c46a5621c698e7b6383ef2a02f4600633d52ba2f4b6fb75c08eed631 languageName: node linkType: hard -"@opentelemetry/instrumentation-fastify@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-fastify@npm:0.43.0" +"@opentelemetry/instrumentation-fastify@npm:^0.47.1": + version: 0.47.1 + resolution: "@opentelemetry/instrumentation-fastify@npm:0.47.1" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/aee85c357ad0f0a88935919aa5bd09547e0b81fd11fc83aabc298fa84e4b3f7d6e64aa03f6273849ce93d11cad591a743a2b73f7838ddf26f54a48b53906259c + checksum: 10/89ffbe54deaa90a33deb873db24967f7e0380c4dc448703ed6b7abbadd345687902e3511e23c1af622ce55e9b70a12e724d3773ad61d7007e4d3d8a47615591d languageName: node linkType: hard -"@opentelemetry/instrumentation-fs@npm:^0.18.0": - version: 0.18.0 - resolution: "@opentelemetry/instrumentation-fs@npm:0.18.0" +"@opentelemetry/instrumentation-fs@npm:^0.22.0": + version: 0.22.0 + resolution: "@opentelemetry/instrumentation-fs@npm:0.22.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/634c23bac8aee7325be2cf2d64f0856d11a9de746f942fec52ebd96a6a7159c63913758c78295c9cb909d950f72c73e1e2685f4d9ed5f9754254ff0ce678dcc6 + checksum: 10/56090810d8c31949ddbd9f1e2c9f91ca38e7214ada60bc9abc72cfac94fb303e5cc905a63e0c1ab2b524aaf80e7a152a3ab286d792fe82bb4e814cd5eb1d2f16 languageName: node linkType: hard -"@opentelemetry/instrumentation-generic-pool@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.42.0" +"@opentelemetry/instrumentation-generic-pool@npm:^0.46.1": + version: 0.46.1 + resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.46.1" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/09c2cf4b64798ce92ddc0214c6c0443bb7800f94a2a8578f2276f3d8a5dd7018b4f5ec9d82d771b4cedd29b949760ca333c1a4fec0d43244ba338af36ad150b2 + checksum: 10/10f8cbf5d052c3cb895857390f6a53ec292a1d0e8ec82df94bfb6cd49a0d0a0db0ba66cbb4127298418be4b68444d048f70833257d37cad404edf17578d477e5 languageName: node linkType: hard -"@opentelemetry/instrumentation-graphql@npm:^0.46.0": - version: 0.46.0 - resolution: "@opentelemetry/instrumentation-graphql@npm:0.46.0" +"@opentelemetry/instrumentation-graphql@npm:^0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-graphql@npm:0.50.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/f7850db04df91a8d213396bbaaf7762535295ac2c572d1338a9798cebfb149ccf3a8b98d9255cdcdbbd42f17228440f2a75f064d2f2010da336174a55b644ec6 + checksum: 10/a359e0839381d74dacf0b3acc8c951686cf73d6201fd305583e1c58ed6f4dcf1421efa322075808ed9c9298af3e579cbe4ac275960ceb7aceb8639b7346b5990 languageName: node linkType: hard -"@opentelemetry/instrumentation-grpc@npm:^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/instrumentation-grpc@npm:0.56.0" +"@opentelemetry/instrumentation-grpc@npm:^0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/instrumentation-grpc@npm:0.202.0" dependencies: - "@opentelemetry/instrumentation": "npm:0.56.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/instrumentation": "npm:0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/00973b36078641afecb085d0bef2dbabef7af3c68bb3abd2a3021600dbaf9a0b86011160c10d2b7db87a0ec21fcd01082547082f8656c94426c2662c29b68613 + checksum: 10/4b59bb35de3b900e9fc5e9ba44d1828b6b4eea15f1ce65a63ad9e047cff5989a9d1d23180e8c221c7bd375c104ecd23f2e7650405e37cf8d8a46edda53d447ee languageName: node linkType: hard -"@opentelemetry/instrumentation-hapi@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-hapi@npm:0.44.0" +"@opentelemetry/instrumentation-hapi@npm:^0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-hapi@npm:0.49.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/d8eafb0213ea8c6971b7a21dd3a3f7ea988954cdf23e708c5fc8bd132267709fd449823d496ac2bb8cf93cf164fa452edb16089c307cefcabb54bc99f20b203e + checksum: 10/2e2640e26ae193000b63fb62aea5dc03eff2c4896442361ebc7e3e482713166bad49616a5d3c157fb8dd0fab908d0c4412e24f4d806b071435890436ccf8fd9f languageName: node linkType: hard -"@opentelemetry/instrumentation-http@npm:^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/instrumentation-http@npm:0.56.0" +"@opentelemetry/instrumentation-http@npm:^0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/instrumentation-http@npm:0.202.0" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/instrumentation": "npm:0.56.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/instrumentation": "npm:0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" forwarded-parse: "npm:2.1.2" - semver: "npm:^7.5.2" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/3fb73d5f0df152f7ff9744a32a521a71656075df1ea6418005a991c912f16fd1b16c468bc9dcc48d4d19621be5b0b4aedc377cf6d00f828e0d2d1f8d4822e6ca + checksum: 10/fb36be7a08a33d07bb51e8c8dc64be937117f03d93a1425bc9ddb041464da1f01914adc1bc8173a145b61a7fd8b6151db8e284db1bcce12135d6b27b01c2ad0a languageName: node linkType: hard -"@opentelemetry/instrumentation-ioredis@npm:^0.46.0": +"@opentelemetry/instrumentation-ioredis@npm:^0.50.1": + version: 0.50.1 + resolution: "@opentelemetry/instrumentation-ioredis@npm:0.50.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/redis-common": "npm:^0.38.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/08e6aed4aa6d0ad0d1dd4a6d02b260f46d1ce5168b8dd1f6b2d3f8c71f0204378e1b52f175817e53cdb6f98841a6ddfc5ca2005592ea678f046316dc4edff281 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-kafkajs@npm:^0.11.0": + version: 0.11.0 + resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.11.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.30.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/6998633cda7260fde928f8691482bdbf5478d7f4c7c0be4c199c366345525733ec87e94b0a38b5b65a719489998f377ad52a065ebe0eeafc010e237533f1ce55 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-knex@npm:^0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-knex@npm:0.47.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.33.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/f3a753505fd6499d05022fbddb0977b781ad41a857df9cde7410273ca3ad9f2343afc6136138bbdde16e5358d77bba66e2ddf7f93d4dab878b6e5b85d72fc6d8 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-koa@npm:^0.50.2": + version: 0.50.2 + resolution: "@opentelemetry/instrumentation-koa@npm:0.50.2" + dependencies: + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/3598afe454d6df1861dd0b7f4a8b617f4d3b89789961577912151df9a2d159523490f25c3e8d03234b5faa62d5f8f8985e8a52b65122cae4c58016debf109edb + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-lru-memoizer@npm:^0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.47.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/91fd11ce2f012b715a1bffb5c81ca5d681e5c2d9f638a2e459f2d4bead587ed755e438c234132484d6d030f0b3104a0747596708f51df109449cd970e965e6ae + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-memcached@npm:^0.46.0": version: 0.46.0 - resolution: "@opentelemetry/instrumentation-ioredis@npm:0.46.0" + resolution: "@opentelemetry/instrumentation-memcached@npm:0.46.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/redis-common": "npm:^0.36.2" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/579296b0fe06c0d727d9866845110b109160579654bb442f4e4ce05df0d47e2ad3912df1ace2bca84423b1d62584524a79d2c3f82943ae7429801e96440c3db5 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-kafkajs@npm:^0.6.0": - version: 0.6.0 - resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.6.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/85723b216fea262d65b6aad9a24242842b0716e06424c6a94a1b9299470c3756dc9d128816f7053bf68eb46bde41d545385e47ac680e2aeff609b3fbc7c6b135 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-knex@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-knex@npm:0.43.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/bb801ba2198b33e0b4feba84313ad54d502969d5fddea9de26ebbeb1a59ade61f03eed2aea983f43682b53102de837916f6dd44eede3a55237980dc99527bf6c - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-koa@npm:^0.46.0": - version: 0.46.0 - resolution: "@opentelemetry/instrumentation-koa@npm:0.46.0" - dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/63d2209e7acb53d7183cd1926656d388a60cca34f3517a26af101acdb4e5612c123071076828a49e18f288a5d694a2f7994f95ee48dab8312f6c2904321d2e4a - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-lru-memoizer@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.43.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/5c1ea5e1f453dea989285199fe8385f31f17982fbc14eb504dc801f5e3a97f8e3fdc4d0f23212ec3cc522e84c1b5750073192b4a33b8a8302cdd18f4935280cb - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-memcached@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-memcached@npm:0.42.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" "@types/memcached": "npm:^2.2.6" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/0f14d19084bdb7327113003998b89b9d0a6ddc91ff7af958799d3f09a7a6ccdb1aa565d58605ced57dc98f72efa465387b8540924a926e5aaf620a3b5feca77a + checksum: 10/12bbcc4b9dcc62b0b48ba83f555112881cc9723f174335bbf7695374ae17582fb12cb2f72295656c84608b73ef5a88afcf551d5c392afebddbf97d7a64230080 languageName: node linkType: hard -"@opentelemetry/instrumentation-mongodb@npm:^0.50.0": - version: 0.50.0 - resolution: "@opentelemetry/instrumentation-mongodb@npm:0.50.0" +"@opentelemetry/instrumentation-mongodb@npm:^0.55.1": + version: 0.55.1 + resolution: "@opentelemetry/instrumentation-mongodb@npm:0.55.1" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/beee37f0be94c614c620ea431ea7315c9293ea14f3b8f751075a5b4d663ed3daa4fe73ef9f58af812ab38d6b59d511da6252386d1fc7aab4d60b4384a8c2065c + checksum: 10/233822b1886b5693923430fb126363005424bcabd03681bf2cf4c035a52dbc6475718417b2a284d38f2fdcac1423625f5a25b767018a3686e9da54f4313f4da9 languageName: node linkType: hard -"@opentelemetry/instrumentation-mongoose@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-mongoose@npm:0.45.0" - dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/a4872b8c7783ace3510f954957aaf6880dee89c00f44a55153e463b5ffeacfdb896ca285cb8b816a746e7dec7f69901d0625c959cbdb09f4dfcba123dfa82213 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-mysql2@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-mysql2@npm:0.44.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@opentelemetry/sql-common": "npm:^0.40.1" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/8ba5e66d3f994a3473df480bfd417b3e870b2fa25ae77b74ed1e516afb4ad38d1625d36c3947b02d9e52298edda1ea5f2df008a7c5bc8543455d760deb9fe3e1 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-mysql@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-mysql@npm:0.44.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@types/mysql": "npm:2.15.26" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/7043e7446280be01ff12c88cbe843d131543c48ee73894b2862e9970cf380b43538f82a31fe32569d1fc2627acf0ccd1635e7ba3858ae93d7163a15b293036a8 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-nestjs-core@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-nestjs-core@npm:0.43.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/8d7170dfb574c77a8f11081aa205c83fb8d8ec7e9935005b1d6ca418b917bc359c55ed955747d330b8d3bdfbc599cc7eac38c0b1c5a092771847f9fd9bf49b3f - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-net@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-net@npm:0.42.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/ef0c3dc42cb75aa3a53c7fc72f214cad9da6276c07ac32cf65a4d9991741cea7daac4a764f7c99d0265aa84b27b8692f77a996cca98dd8a67dd299bfcd8a85a6 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-pg@npm:^0.49.0": +"@opentelemetry/instrumentation-mongoose@npm:^0.49.0": version: 0.49.0 - resolution: "@opentelemetry/instrumentation-pg@npm:0.49.0" + resolution: "@opentelemetry/instrumentation-mongoose@npm:0.49.0" dependencies: - "@opentelemetry/core": "npm:^1.26.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:1.27.0" - "@opentelemetry/sql-common": "npm:^0.40.1" - "@types/pg": "npm:8.6.1" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/4b2b320346a0d00a56438c041ddda6cbd8b34d37de613daab618892fcba380b0cbd5396886028e9e2ac81c497f25e66f7668ccbf57c3f870678d30fc16e4ae24 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mysql2@npm:^0.48.1": + version: 0.48.1 + resolution: "@opentelemetry/instrumentation-mysql2@npm:0.48.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/sql-common": "npm:^0.41.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/d52d0950201adb3c4ce8f82edc544eee489de0971045f1e907832d6e7424d372da3a1e62143f6fcde698d883dfbe7adbea243cef9653f467c96d011d98225676 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mysql@npm:^0.48.1": + version: 0.48.1 + resolution: "@opentelemetry/instrumentation-mysql@npm:0.48.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/mysql": "npm:2.15.27" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/8e4493e5a685d98f0b7797b6f3996f7949cdae758e68c12e2edb57d8388be47a67e668c12340f1a2e18c692c8db990a765913120e402215c8d473695c9a281b8 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-nestjs-core@npm:^0.48.1": + version: 0.48.1 + resolution: "@opentelemetry/instrumentation-nestjs-core@npm:0.48.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.30.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/fbbd5dd411b79371725e9075bca0c492a524ebd90d5e17434c3608bae6ec1cbbd5cca4dc0385c423e59963bfc1b945efdff5cd02f09a3f2a06391fc176d52c50 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-net@npm:^0.46.1": + version: 0.46.1 + resolution: "@opentelemetry/instrumentation-net@npm:0.46.1" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/3372ac7b8643c4adea2d8ffd762a2c872e02d000d5cc5afca922f422033eea251adeeac1c5d1bd49014d76c9167a0dfa98cd41dda7b3950395c179a8a8c6de81 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-oracledb@npm:^0.28.0": + version: 0.28.0 + resolution: "@opentelemetry/instrumentation-oracledb@npm:0.28.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/oracledb": "npm:6.5.2" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/820a6e760d2137ad00b27ff78014316fc37e92f2be94ad4c6082e92ace8fcd89a6d2bcc744e6330358ebd0f127d7993b65843b167b0c1ea0f8d5cb0fe201c634 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-pg@npm:^0.54.1": + version: 0.54.1 + resolution: "@opentelemetry/instrumentation-pg@npm:0.54.1" + dependencies: + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/sql-common": "npm:^0.41.0" + "@types/pg": "npm:8.15.4" "@types/pg-pool": "npm:2.0.6" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/04457e441872a0afecfa471f04bbecdf4b62782d110cd1a75423f9ff12c34396896056dda99923690f4a26c572fccc0c28d25fbd26e71f07ca2778e61fc3a7d1 + checksum: 10/eb88b8bd4417db8188af44e62659a7bc35b3f6a4b155d12c69357fc88185f3d719b3dd93e5562896088d07041c882a71a06d9672c14332846ae4f5abd26ec99a languageName: node linkType: hard -"@opentelemetry/instrumentation-pino@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-pino@npm:0.45.0" +"@opentelemetry/instrumentation-pino@npm:^0.49.1": + version: 0.49.1 + resolution: "@opentelemetry/instrumentation-pino@npm:0.49.1" dependencies: - "@opentelemetry/api-logs": "npm:^0.56.0" - "@opentelemetry/core": "npm:^1.25.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/api-logs": "npm:^0.202.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/ef56a6bca54e99e66531576727ce236bd743413434fa04bb759ae6ebf8564fba303f3756ee7333fdaaea61a72a7e29f21ae19267c16e6d2d651596970b07ff10 + checksum: 10/2e2bff24bef74f68da8f4b4655d198c3fba7f7425f2f6317077385bd34dfbfb44c3747165859fec7a9f90aa0c77f830148e112e3d8257f6ac35dc28bbe157041 languageName: node linkType: hard -"@opentelemetry/instrumentation-redis-4@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-redis-4@npm:0.45.0" +"@opentelemetry/instrumentation-redis@npm:^0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-redis@npm:0.50.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/instrumentation": "npm:^0.202.0" + "@opentelemetry/redis-common": "npm:^0.38.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/8e2cd153936681b9a1e13a1e059df18d31a8d2a85c0db11e3d3b00c496f360efe3c864acac9e87de80cc13318f17ce35ecfe0aea22d502b42109cd1164e39619 + checksum: 10/94a05b1401fa071c2483d241a0cffb3fc79492c44ee7a2d2e320118cbc948eb7972c70e93f128bae29febd4958fc95904afff56b5c49da8b5407666e8f26e748 languageName: node linkType: hard -"@opentelemetry/instrumentation-redis@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-redis@npm:0.45.0" +"@opentelemetry/instrumentation-restify@npm:^0.48.2": + version: 0.48.2 + resolution: "@opentelemetry/instrumentation-restify@npm:0.48.2" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/8bb137bc04be5b6d4afef365c5c52d8148c65f40c77af2010173ae2c481a85a24e9d1ffe36821315af7f177ba22f32f05b5d017d1cbcf1c298f4bbf3dff56d8a + checksum: 10/b2a0917248ae9defaff8dd9d5c650fb627241b56355474a776a54fd9541a29b3bbb487b54dba7042ac2f7e15cb0a79f738360fe8a3322e4066ff06728e027292 languageName: node linkType: hard -"@opentelemetry/instrumentation-restify@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-restify@npm:0.44.0" +"@opentelemetry/instrumentation-router@npm:^0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-router@npm:0.47.0" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/be37a7f3aeaa085e8ed3f3cddcc8cd6616a73f865337b5a5e086cc05161b258a01ee45cc41e22d2f8c8a9d2254be04c8d3b866b31b76315cf3087a8b0914c864 + checksum: 10/620a54e97e311692c197e86f12bf43bf1a04f2b3009f71dfdf6e0972b5c282606cc649739ba0041f60aea3fae9b027b315378e71a5f764c85952ece2e5b28078 languageName: node linkType: hard -"@opentelemetry/instrumentation-router@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-router@npm:0.43.0" +"@opentelemetry/instrumentation-runtime-node@npm:^0.16.0": + version: 0.16.0 + resolution: "@opentelemetry/instrumentation-runtime-node@npm:0.16.0" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/85d5a1302558fc99d5ec411ef4ea7306bb2c5295807ef3e75f61272b46be1752a19de145d22dbe530803ddfef65a4811ecccb5944183302ff60b8762005de70d + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-socket.io@npm:^0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-socket.io@npm:0.49.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/3c2670151a24528910b15b85e3f8ec69468170d35ffe574850dbafee1efb055a14c6d231ccda03151870add4976c9da41171190aff859ca993be514fd5c6e104 + checksum: 10/16ab1664c3692267a6b9d0fdaf9256d66d9b705c056c019fb15d261d1f09296d325ddbbc9402b60b0d3b5722b55cdb6c7d0980c8ee965ef4346461742cdf87a1 languageName: node linkType: hard -"@opentelemetry/instrumentation-socket.io@npm:^0.45.0": - version: 0.45.0 - resolution: "@opentelemetry/instrumentation-socket.io@npm:0.45.0" +"@opentelemetry/instrumentation-tedious@npm:^0.21.1": + version: 0.21.1 + resolution: "@opentelemetry/instrumentation-tedious@npm:0.21.1" dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/fa0550011cde7a06f5c25f655c9ea1d0df284d63e2eb61599add27a16225d952b2c573364478654f9a0694f4716334f5618ffa9e8991bb078b202b78041cd7c0 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-tedious@npm:^0.17.0": - version: 0.17.0 - resolution: "@opentelemetry/instrumentation-tedious@npm:0.17.0" - dependencies: - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" "@types/tedious": "npm:^4.0.14" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/62594f42fddc7af06aa14575e70d821551842671d2f2013e583d58d508d6ca8e6749faf89453e8254e6257483390cf8fd9ca0076327850d54e088d436f13ac51 + checksum: 10/5347d20e2cb4e07a1d25275edb25c47dcf87700a19de630fb33b7fc06bda0eb5934fb058fcb15b33be2eeb49a7430720c011f8540405b5ee10d22e689c93b94a languageName: node linkType: hard -"@opentelemetry/instrumentation-undici@npm:^0.9.0": - version: 0.9.0 - resolution: "@opentelemetry/instrumentation-undici@npm:0.9.0" +"@opentelemetry/instrumentation-undici@npm:^0.13.2": + version: 0.13.2 + resolution: "@opentelemetry/instrumentation-undici@npm:0.13.2" dependencies: - "@opentelemetry/core": "npm:^1.8.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.7.0 - checksum: 10/e7300fb0353cc0648cc8a1779287e6780b6aaf3b4f13698a203367cfb9d571677e8f5897b3e79cfede196e72007ac2a1f4fbb8128a61ceb2b85517ebb30effd4 + checksum: 10/9f806706096d629796d1205a0f2a9f18cf3542f61dfb60f20199ca5ba269044145a593f5ee0ad495b046eb01b8a14448a61a8bbe6a18611f6967f3473923d97e languageName: node linkType: hard -"@opentelemetry/instrumentation-winston@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-winston@npm:0.43.0" +"@opentelemetry/instrumentation-winston@npm:^0.47.0": + version: 0.47.0 + resolution: "@opentelemetry/instrumentation-winston@npm:0.47.0" dependencies: - "@opentelemetry/api-logs": "npm:^0.56.0" - "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/api-logs": "npm:^0.202.0" + "@opentelemetry/instrumentation": "npm:^0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/9cd8e4b047bea576e6277c911d1f44df2b880b2c9f01081fff9b5ee4f1131dd6dd481ee11ab887344d22535211af1f6a75bcd9c34185183855acdd12975024ca + checksum: 10/1a046490c1509f77ae70552ef6cdbf6c21baba4f5d6f45e0c473ffa102156b009acd20036dafbf5d29e92132df88c4aad078b62606af3bda0fbdd4ab90073937 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation@npm:0.202.0, @opentelemetry/instrumentation@npm:^0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/instrumentation@npm:0.202.0" + dependencies: + "@opentelemetry/api-logs": "npm:0.202.0" + import-in-the-middle: "npm:^1.8.1" + require-in-the-middle: "npm:^7.1.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/da1db1ebc4ca847cc68d894b2e3a6c6552851d93af8ea793d42474e920f710664575c8991dc269e1a83fcf8f5abdda2cc724fa24e9cc4ae19fa6f70eb68ffc0e languageName: node linkType: hard @@ -14363,19 +14312,15 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/instrumentation@npm:0.56.0, @opentelemetry/instrumentation@npm:^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/instrumentation@npm:0.56.0" +"@opentelemetry/otlp-exporter-base@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/otlp-exporter-base@npm:0.202.0" dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@types/shimmer": "npm:^1.2.0" - import-in-the-middle: "npm:^1.8.1" - require-in-the-middle: "npm:^7.1.1" - semver: "npm:^7.5.2" - shimmer: "npm:^1.2.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-transformer": "npm:0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/7c3802eb6b55b39b6904526d052b918619c9cde0f71a35bc2f23ac6c3a10ea66b08a65adf6862cdbaac7b231fb5119204b4d5531be25b96933a9d8b91a9ce062 + checksum: 10/229778895ba1971451a8b1ec8a4787b0cdba337c87f3ca6aaf6d649f5e2b26439ba1befa36d31824fffa3cef62382792680ec70194f57aac6ebe98e95acecc69 languageName: node linkType: hard @@ -14391,15 +14336,17 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/otlp-exporter-base@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/otlp-exporter-base@npm:0.56.0" +"@opentelemetry/otlp-grpc-exporter-base@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/otlp-grpc-exporter-base@npm:0.202.0" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" + "@grpc/grpc-js": "npm:^1.7.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/otlp-exporter-base": "npm:0.202.0" + "@opentelemetry/otlp-transformer": "npm:0.202.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/a640641ae86a9dceeecb84e32e4b8cd56be9d2af202e44ad84022380530bcda4b27b4f7089b87238db8088930256550d385aeca200369021a8085e1288ef34db + checksum: 10/ba52acee1d46c3bca38d6eba8fea41d5c7389c26a34dd7ed4f4fbc46da5fcbf109ae139c5149c9730cd076ba51d4933d9bc06c223470ee8a463a31fed75b4ed6 languageName: node linkType: hard @@ -14417,17 +14364,20 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/otlp-grpc-exporter-base@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/otlp-grpc-exporter-base@npm:0.56.0" +"@opentelemetry/otlp-transformer@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/otlp-transformer@npm:0.202.0" dependencies: - "@grpc/grpc-js": "npm:^1.7.1" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/otlp-exporter-base": "npm:0.56.0" - "@opentelemetry/otlp-transformer": "npm:0.56.0" + "@opentelemetry/api-logs": "npm:0.202.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-logs": "npm:0.202.0" + "@opentelemetry/sdk-metrics": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" + protobufjs: "npm:^7.3.0" peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10/8dd8117357035fff225d23637d0d2298b842f1b5611bf17612aff666a41068ad4d986868818a501a2136f91d788905fb99952b19d60e96fd08f2898422dc22a3 + checksum: 10/67e189af60bf8308a5b93deb85bef9709a5604b8c7915d0d42a7a2bff932b7257dfdfc071812c77913e136955a985ffe838c72b5f10059021087ea0bc52d84cd languageName: node linkType: hard @@ -14448,29 +14398,12 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/otlp-transformer@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/otlp-transformer@npm:0.56.0" - dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-logs": "npm:0.56.0" - "@opentelemetry/sdk-metrics": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" - protobufjs: "npm:^7.3.0" - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 10/d673b0295fac96b45535e86dea54c7c8e1270c161579de908cf7724fee00f4d5b49652da0a886dcac49c5d12a0d8f2b8be1cf639f4094bc0d16eec7808bddb78 - languageName: node - linkType: hard - -"@opentelemetry/propagation-utils@npm:^0.30.14": - version: 0.30.16 - resolution: "@opentelemetry/propagation-utils@npm:0.30.16" +"@opentelemetry/propagation-utils@npm:^0.31.2": + version: 0.31.2 + resolution: "@opentelemetry/propagation-utils@npm:0.31.2" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/8d282553d08aadfc9f8879ea6fbb33089765a535f960d72ae27fb98e8dab9c7e0394217cb9e2999479f9c2486fa9454cf4ffffeda30f4a96f8fe011276942b75 + checksum: 10/13828caae31651a1c4fa736f254b49a46b62348ff9ece945b19253fb52562db08bd268b5b0944ef3d2cb951f20cd4118ba14158b34a192e63868f0f3aa9c7cc9 languageName: node linkType: hard @@ -14485,14 +14418,14 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/propagator-b3@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/propagator-b3@npm:1.29.0" +"@opentelemetry/propagator-b3@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/propagator-b3@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" + "@opentelemetry/core": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/002e9400d9b605f1af1140dc4d20579d1494d7eb4c93e72862ee5207cc46cd3ed54f41eb42a0a00f0676b3e8f0f1afb2df36918582d833c97fbf4a23f5632f75 + checksum: 10/9871854b3d7516273c1f867c7a6a8eac5791f77954edf7509cc320ee6c109de8ef44778076edd4a64421b84f31632e4d283cb685f9220c5e7f1fe823c0e81a06 languageName: node linkType: hard @@ -14507,87 +14440,87 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/propagator-jaeger@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/propagator-jaeger@npm:1.29.0" +"@opentelemetry/propagator-jaeger@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/propagator-jaeger@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" + "@opentelemetry/core": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/75849bcfaa60823cc8b2bb10a4094ef7d933d998c84977f8319930ed7fdba37aba5906ba56f5ed96f28e07bb2cf5e185b7340993c06a36135a1de25de945df74 + checksum: 10/d6a51e7dd58dde7ada4c0fe510a14f9a33f1972f0db11b64fccb867be23652d4d8a55012dd5a295753ad27c456b21d502eb3a24dfbce6a0a3304e1fa6e1f4896 languageName: node linkType: hard -"@opentelemetry/redis-common@npm:^0.36.2": - version: 0.36.2 - resolution: "@opentelemetry/redis-common@npm:0.36.2" - checksum: 10/e7f610f79c95bab9156a9831162c7b55b94ab43c5e47ecb9efcc10c08a236395fdd54b6bb018da981e6641bac9da6fda1b50636fb49db584e87d988750d255e1 +"@opentelemetry/redis-common@npm:^0.38.0": + version: 0.38.0 + resolution: "@opentelemetry/redis-common@npm:0.38.0" + checksum: 10/c7caa450ed27ad02aeefa3e4d643e7d065d76e5f1cd275c8c3d0c7d324bf7d06434666dbd836d219f6b2e1057285f30ccaa89b949438b38118a70786ec31fa52 languageName: node linkType: hard -"@opentelemetry/resource-detector-alibaba-cloud@npm:^0.29.6": - version: 0.29.7 - resolution: "@opentelemetry/resource-detector-alibaba-cloud@npm:0.29.7" +"@opentelemetry/resource-detector-alibaba-cloud@npm:^0.31.2": + version: 0.31.2 + resolution: "@opentelemetry/resource-detector-alibaba-cloud@npm:0.31.2" dependencies: - "@opentelemetry/core": "npm:^1.26.0" - "@opentelemetry/resources": "npm:^1.10.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/resources": "npm:^2.0.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/1baba0bef0201b4b6f442e3dd47846051b551e5dd0d9c9aaf6223ff292ae719f9263edb81496487166956a5ad67f79f73dda65ec012912f2fab9758fe1199656 + checksum: 10/1e2498d5dc970addaeb88c9a1c4be85248438fe69876f2223ee526535ccb50d1ffaca366bfc5c03d0c84933050fd5d821726d8ce92ac5829da18f4a91025ce2f languageName: node linkType: hard -"@opentelemetry/resource-detector-aws@npm:^1.9.0": - version: 1.12.0 - resolution: "@opentelemetry/resource-detector-aws@npm:1.12.0" +"@opentelemetry/resource-detector-aws@npm:^2.2.0": + version: 2.2.0 + resolution: "@opentelemetry/resource-detector-aws@npm:2.2.0" dependencies: - "@opentelemetry/core": "npm:^1.0.0" - "@opentelemetry/resources": "npm:^1.10.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/resources": "npm:^2.0.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/95702aed5d2a22fab0429439d57ede5c53b3512618af21ffc098b0e6fca86266e9703a32325427082bb5776697d5e74a4e99f6c757e4b6bcf497e32663e705f9 + checksum: 10/91e6b67936d6846ba98b31438a9f32e5486f27153cfcd57978c8b6c5df9cc400c821ea63b06fff158c6a7e97b3ded3396f91f02410f28d4113d6b5bdf75f2bec languageName: node linkType: hard -"@opentelemetry/resource-detector-azure@npm:^0.4.0": - version: 0.4.0 - resolution: "@opentelemetry/resource-detector-azure@npm:0.4.0" +"@opentelemetry/resource-detector-azure@npm:^0.9.0": + version: 0.9.0 + resolution: "@opentelemetry/resource-detector-azure@npm:0.9.0" dependencies: - "@opentelemetry/core": "npm:^1.25.1" - "@opentelemetry/resources": "npm:^1.10.1" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/resources": "npm:^2.0.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/e48408787b9834b0079690d7e5505dd5aad6a2234e61324ae8a84237b26c79c4b585cac93c1aab280be63f4c9ef32b74923858771c7363211036bfebee7a6234 + checksum: 10/93d85781e73f37ab186b8d39ad144c944d80e69d19361ef4f846499e2bf0ba27df2cd00e334b1408415c80488f1633764696e1d29b639ed7829631ec29c92286 languageName: node linkType: hard -"@opentelemetry/resource-detector-container@npm:^0.5.2": - version: 0.5.3 - resolution: "@opentelemetry/resource-detector-container@npm:0.5.3" +"@opentelemetry/resource-detector-container@npm:^0.7.2": + version: 0.7.2 + resolution: "@opentelemetry/resource-detector-container@npm:0.7.2" dependencies: - "@opentelemetry/core": "npm:^1.26.0" - "@opentelemetry/resources": "npm:^1.10.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/resources": "npm:^2.0.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/79fd039e3f960a8fa31af9df52bffc948c3bc2f384d574061f0e0c47fa9bdb0d4b95ff34e94f72b33746a92a427cf284c069633ad07bfdca52c62e03e5d005c5 + checksum: 10/d556c4f64737726e31f211c6163ea359e403b4b0c65bca9fff565ec6a579a18340f4c6dc68d78ac707413c44bcb5f2a362eab2794fbd99524faf161517793e0e languageName: node linkType: hard -"@opentelemetry/resource-detector-gcp@npm:^0.31.0": - version: 0.31.0 - resolution: "@opentelemetry/resource-detector-gcp@npm:0.31.0" +"@opentelemetry/resource-detector-gcp@npm:^0.36.0": + version: 0.36.0 + resolution: "@opentelemetry/resource-detector-gcp@npm:0.36.0" dependencies: - "@opentelemetry/core": "npm:^1.0.0" - "@opentelemetry/resources": "npm:^1.10.0" + "@opentelemetry/core": "npm:^2.0.0" + "@opentelemetry/resources": "npm:^2.0.0" "@opentelemetry/semantic-conventions": "npm:^1.27.0" gcp-metadata: "npm:^6.0.0" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 10/3ad40b7633dd106bac3f7ef27265d88b0fbb197f3754469b3a334e0973335da0e432f9b740a18e8b2731358da565f0a330e60fbf446ac00855bc262fcd75e07d + checksum: 10/9bfffd5d21a90509bc8d4dd3ae27554dd56719ca1607fcc20900034cc5776ff4c0025a3d4fddbd7c12e7962dd747516bdca9a9da6ccc59223c8d485609aea732 languageName: node linkType: hard @@ -14603,27 +14536,28 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/resources@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/resources@npm:1.29.0" +"@opentelemetry/resources@npm:2.0.1, @opentelemetry/resources@npm:^2.0.0": + version: 2.0.1 + resolution: "@opentelemetry/resources@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/677b9e3478a380e93383a223a01ccade21dde7381924a4f859b2309ea82e79da9e7257338791a5b2699f763b0c198ec7e0ed6a12f03e467f5e0d8287757f0f66 + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10/282f3831de2755d0fda2d8b6e37f9587ea248066d50c7d2f14c803ac9d5262a0f1db98a4185bcdc5acaeeece0b61f4fce43bc3896a79f1da79045ae4928618bf languageName: node linkType: hard -"@opentelemetry/resources@npm:^1.10.0, @opentelemetry/resources@npm:^1.10.1, @opentelemetry/resources@npm:^1.24.0": - version: 1.30.1 - resolution: "@opentelemetry/resources@npm:1.30.1" +"@opentelemetry/sdk-logs@npm:0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/sdk-logs@npm:0.202.0" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/api-logs": "npm:0.202.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/9b7544b639e8fee41315e2646615676ffb1020dba0f6c81e6ec1dd2daf5409fc6ce3d2b629bbd9cd32f85decc3a8bfa5dc8cc52bb72bd84c1777ca25b4301aa0 + "@opentelemetry/api": ">=1.4.0 <1.10.0" + checksum: 10/e1b76647282a41ad7004c86c0058b0e9be70fdcf34aa2761929401e274af79bc5e3c6610a63e14fde4d51d96d8c96adaf3247c10b9a64cb70086d2ede2e421ca languageName: node linkType: hard @@ -14640,19 +14574,6 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/sdk-logs@npm:0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/sdk-logs@npm:0.56.0" - dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/resources": "npm:1.29.0" - peerDependencies: - "@opentelemetry/api": ">=1.4.0 <1.10.0" - checksum: 10/36f7ef72ce9f1ccc6f8bb1b99a142801bb3e6e4e2f2dda30de713144213c62b144530bb49590379bc413757c8d170fba874619d933f42d0370c5473c22fdeea0 - languageName: node - linkType: hard - "@opentelemetry/sdk-metrics@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/sdk-metrics@npm:1.27.0" @@ -14665,15 +14586,47 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/sdk-metrics@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/sdk-metrics@npm:1.29.0" +"@opentelemetry/sdk-metrics@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/sdk-metrics@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/resources": "npm:1.29.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + peerDependencies: + "@opentelemetry/api": ">=1.9.0 <1.10.0" + checksum: 10/eb23d0657ce7ef0784f6c89af650de83530099782758fce574316a8e82ff2bca0eb3adffa88c5fdd04eaced6150deb53ea0ea05aae06d2783795691734e85473 + languageName: node + linkType: hard + +"@opentelemetry/sdk-node@npm:^0.202.0": + version: 0.202.0 + resolution: "@opentelemetry/sdk-node@npm:0.202.0" + dependencies: + "@opentelemetry/api-logs": "npm:0.202.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/exporter-logs-otlp-grpc": "npm:0.202.0" + "@opentelemetry/exporter-logs-otlp-http": "npm:0.202.0" + "@opentelemetry/exporter-logs-otlp-proto": "npm:0.202.0" + "@opentelemetry/exporter-metrics-otlp-grpc": "npm:0.202.0" + "@opentelemetry/exporter-metrics-otlp-http": "npm:0.202.0" + "@opentelemetry/exporter-metrics-otlp-proto": "npm:0.202.0" + "@opentelemetry/exporter-prometheus": "npm:0.202.0" + "@opentelemetry/exporter-trace-otlp-grpc": "npm:0.202.0" + "@opentelemetry/exporter-trace-otlp-http": "npm:0.202.0" + "@opentelemetry/exporter-trace-otlp-proto": "npm:0.202.0" + "@opentelemetry/exporter-zipkin": "npm:2.0.1" + "@opentelemetry/instrumentation": "npm:0.202.0" + "@opentelemetry/propagator-b3": "npm:2.0.1" + "@opentelemetry/propagator-jaeger": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/sdk-logs": "npm:0.202.0" + "@opentelemetry/sdk-metrics": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" + "@opentelemetry/sdk-trace-node": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ">=1.3.0 <1.10.0" - checksum: 10/399f28da37d7176f4017cffb2b9c3d3db65bbe397e5f7232c0b2df1a9162f094d7e460e64058c959aca787a80d48e0f98b9b65dfb711b72f41fa04b5b03b0e23 + checksum: 10/80e3c6493bb5d87e5ce9c8b25dc5e2614c879b2ebe4f79f1a373d8237085b6e0bcaaff06acf01528e45849fb27e38cc0961fde6c87d7d2addf90cbcfbea43af7 languageName: node linkType: hard @@ -14703,32 +14656,6 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/sdk-node@npm:^0.56.0": - version: 0.56.0 - resolution: "@opentelemetry/sdk-node@npm:0.56.0" - dependencies: - "@opentelemetry/api-logs": "npm:0.56.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/exporter-logs-otlp-grpc": "npm:0.56.0" - "@opentelemetry/exporter-logs-otlp-http": "npm:0.56.0" - "@opentelemetry/exporter-logs-otlp-proto": "npm:0.56.0" - "@opentelemetry/exporter-trace-otlp-grpc": "npm:0.56.0" - "@opentelemetry/exporter-trace-otlp-http": "npm:0.56.0" - "@opentelemetry/exporter-trace-otlp-proto": "npm:0.56.0" - "@opentelemetry/exporter-zipkin": "npm:1.29.0" - "@opentelemetry/instrumentation": "npm:0.56.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/sdk-logs": "npm:0.56.0" - "@opentelemetry/sdk-metrics": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" - "@opentelemetry/sdk-trace-node": "npm:1.29.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" - peerDependencies: - "@opentelemetry/api": ">=1.3.0 <1.10.0" - checksum: 10/ba89ba4ef5ba7b4d75fb167b4bc5247602202d85d0da431c863932a83a313bd82aaad00f0fb3f3ef75a47242c474a5066a967649a585ee0f7cdbec6ddedfa39b - languageName: node - linkType: hard - "@opentelemetry/sdk-trace-base@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/sdk-trace-base@npm:1.27.0" @@ -14742,16 +14669,16 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/sdk-trace-base@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/sdk-trace-base@npm:1.29.0" +"@opentelemetry/sdk-trace-base@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/sdk-trace-base@npm:2.0.1" dependencies: - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/resources": "npm:1.29.0" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/resources": "npm:2.0.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/97080188cd2ded16cc489ad5414255f0e63a81ca3f8778f604cdb1409bf95691529d7f9233d37788ac14a6ff36b736fcf274ef39bba3fdf421e7201642d2d5b4 + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10/9de1e36bbce9bd7c0563e6395765fffc0f8c78806cb33cc95267e98dffd82de33857a51288073a104c10418b934e51560bcb5dcaf4e63e5c9e096f65cadd42cd languageName: node linkType: hard @@ -14771,19 +14698,16 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/sdk-trace-node@npm:1.29.0": - version: 1.29.0 - resolution: "@opentelemetry/sdk-trace-node@npm:1.29.0" +"@opentelemetry/sdk-trace-node@npm:2.0.1": + version: 2.0.1 + resolution: "@opentelemetry/sdk-trace-node@npm:2.0.1" dependencies: - "@opentelemetry/context-async-hooks": "npm:1.29.0" - "@opentelemetry/core": "npm:1.29.0" - "@opentelemetry/propagator-b3": "npm:1.29.0" - "@opentelemetry/propagator-jaeger": "npm:1.29.0" - "@opentelemetry/sdk-trace-base": "npm:1.29.0" - semver: "npm:^7.5.2" + "@opentelemetry/context-async-hooks": "npm:2.0.1" + "@opentelemetry/core": "npm:2.0.1" + "@opentelemetry/sdk-trace-base": "npm:2.0.1" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10/4af09076649bdfbd1b3b12a8d0f9fd9569cb8e821f449a9096aa64253970ab57188d93eb7fcb108c9067e8e7deadf79cdd5146939493d35795e0e66fb9d64aae + checksum: 10/7c5b4a902ba88ef03f02da83f6900080d81bb3264752419981dc44faabfe2bf4dbe91d25fec4a671afd5212151eee535a5205137772a8fd2c8d247950eb6556f languageName: node linkType: hard @@ -14801,49 +14725,28 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:^1.27.0, @opentelemetry/semantic-conventions@npm:~1.30.0": +"@opentelemetry/semantic-conventions@npm:^1.27.0, @opentelemetry/semantic-conventions@npm:^1.29.0, @opentelemetry/semantic-conventions@npm:^1.30.0, @opentelemetry/semantic-conventions@npm:^1.33.1, @opentelemetry/semantic-conventions@npm:^1.34.0": + version: 1.34.0 + resolution: "@opentelemetry/semantic-conventions@npm:1.34.0" + checksum: 10/1892b4cc69c9e00456c809604a980e32696563e96463ff5f9d07e72d5aca73836a7378090509f28f54445ac6e072d2343a888c9d64d9ce287198e899082ff7aa + languageName: node + linkType: hard + +"@opentelemetry/semantic-conventions@npm:~1.30.0": version: 1.30.0 resolution: "@opentelemetry/semantic-conventions@npm:1.30.0" checksum: 10/78df5976f5bcfd00acaea3e609cf06fdd34517ae8db994ae216aaac16c51af97ac22c534bfcbac5218e0086db83ec5ef6cc045b95626cc6ea807686bea549a41 languageName: node linkType: hard -"@opentelemetry/sql-common@npm:^0.40.1": - version: 0.40.1 - resolution: "@opentelemetry/sql-common@npm:0.40.1" +"@opentelemetry/sql-common@npm:^0.41.0": + version: 0.41.0 + resolution: "@opentelemetry/sql-common@npm:0.41.0" dependencies: - "@opentelemetry/core": "npm:^1.1.0" + "@opentelemetry/core": "npm:^2.0.0" peerDependencies: "@opentelemetry/api": ^1.1.0 - checksum: 10/f887b4135be56c9ef6e29f040c9f75f34709e38c11897d59d284d7e73175a2dd2c6267c18061144e81a0045fc461b7813769db2e49c42a8d6becc58b1456d55c - languageName: node - linkType: hard - -"@oriflame/backstage-plugin-score-card@npm:^0.9.0": - version: 0.9.1 - resolution: "@oriflame/backstage-plugin-score-card@npm:0.9.1" - dependencies: - "@backstage/catalog-model": "npm:^1.4.3" - "@backstage/config": "npm:^1.1.1" - "@backstage/core-components": "npm:^0.13.10" - "@backstage/core-plugin-api": "npm:^1.8.2" - "@backstage/integration": "npm:^1.9.0" - "@backstage/integration-react": "npm:^1.1.24" - "@backstage/plugin-catalog-common": "npm:^1.0.20" - "@backstage/plugin-catalog-react": "npm:^1.9.3" - "@backstage/theme": "npm:^0.5.0" - "@backstage/types": "npm:^1.1.1" - "@backstage/version-bridge": "npm:^1.0.7" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.11.2" - "@material-ui/lab": "npm:^4.0.0-alpha.57" - "@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0" - react-use: "npm:^17.2.4" - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 10/549e9d754f5607ebe89a717b75f12333a49b7d87e9b469260675de2c77b7991b1600a11d200b0c6f1922f981df8398abb9389cbceb21ee46646c8604e8892319 + checksum: 10/182915f050b8b685f5499e9fa4ed9a9730fcd404889e5066cfc7d94e9961b1f2780216d776070a4a5c1b94323c287ab426b06f5a8828d5fea3daf664bfd397bb languageName: node linkType: hard @@ -14864,13 +14767,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.53.1 - resolution: "@playwright/test@npm:1.53.1" + version: 1.53.2 + resolution: "@playwright/test@npm:1.53.2" dependencies: - playwright: "npm:1.53.1" + playwright: "npm:1.53.2" bin: playwright: cli.js - checksum: 10/98fb9b962710183d465b695daab2006296fd9a703ecb1b763a38cd12a39f7d6066f9539d1758e54313d393353fafb16b90fb31e4add1ca99ffec99b8b1b40fb9 + checksum: 10/063c4fd82e5022db7f53e85a3b31caa1c302e7d3f874b3acc751ee5fcf8f102068693e393dc5146cdeeb5850f2321366de4ebc5ef12ab81dae52e2c7113a6b49 languageName: node linkType: hard @@ -16498,22 +16401,6 @@ __metadata: languageName: node linkType: hard -"@react-hookz/web@npm:^23.0.0": - version: 23.1.0 - resolution: "@react-hookz/web@npm:23.1.0" - dependencies: - "@react-hookz/deep-equal": "npm:^1.0.4" - peerDependencies: - js-cookie: ^3.0.5 - react: ^16.8 || ^17 || ^18 - react-dom: ^16.8 || ^17 || ^18 - peerDependenciesMeta: - js-cookie: - optional: true - checksum: 10/7f345fc286ee3bae74b76b909898213a589250856783805d0356d8ef9ca0e3d1638e7499d8b77ae1dff6350dec230fda468e0e4c8fc05a9997902569d3d81b49 - languageName: node - linkType: hard - "@react-hookz/web@npm:^24.0.0": version: 24.0.4 resolution: "@react-hookz/web@npm:24.0.4" @@ -17956,41 +17843,41 @@ __metadata: languageName: node linkType: hard -"@shikijs/engine-oniguruma@npm:^3.4.0": - version: 3.4.0 - resolution: "@shikijs/engine-oniguruma@npm:3.4.0" +"@shikijs/engine-oniguruma@npm:^3.7.0": + version: 3.7.0 + resolution: "@shikijs/engine-oniguruma@npm:3.7.0" dependencies: - "@shikijs/types": "npm:3.4.0" + "@shikijs/types": "npm:3.7.0" "@shikijs/vscode-textmate": "npm:^10.0.2" - checksum: 10/3f6c33a1f49e6a8235b79029e3e95f0bc95398f299e53b96a23942ceb4648be51071f48b8632e2f244b2b2477d152035fd18bc4b7e34abe885d84e94698f7e94 + checksum: 10/dee77bddb90efd2b164d46ed2b88793503d00cd2fb484b869cf7c78531b75fd024bbbd2d7b8be2eb3f063179d79aa441341478411403415156ad76672d751547 languageName: node linkType: hard -"@shikijs/langs@npm:^3.4.0": - version: 3.4.0 - resolution: "@shikijs/langs@npm:3.4.0" +"@shikijs/langs@npm:^3.7.0": + version: 3.7.0 + resolution: "@shikijs/langs@npm:3.7.0" dependencies: - "@shikijs/types": "npm:3.4.0" - checksum: 10/355065accab578a8a017ee238f13ee0b6adf007b514f78d7ea126f07ee89cd682f1f377f49d923688c6787b474b5b3a640aa3b083ac11ea11ea4edd7e8c50ac7 + "@shikijs/types": "npm:3.7.0" + checksum: 10/11bc671751c6cd82ae83575bdf84ecf51f54b13b3c8e3b51ff299a8c1288b8eac0fa2c99c6905753a4790b7af9160c6ed5a15be4c54851be3d339540a8d292ee languageName: node linkType: hard -"@shikijs/themes@npm:^3.4.0": - version: 3.4.0 - resolution: "@shikijs/themes@npm:3.4.0" +"@shikijs/themes@npm:^3.7.0": + version: 3.7.0 + resolution: "@shikijs/themes@npm:3.7.0" dependencies: - "@shikijs/types": "npm:3.4.0" - checksum: 10/74e5911548d77a63375125575db77dd62b44c40afd39f168bc3fc4d7fefb4d2922f49cf76d21139d850a02a5e207659a247a417be27b438d3d5ea80abe450e52 + "@shikijs/types": "npm:3.7.0" + checksum: 10/9fb5085bc9121124577823a28f9b2d1335875296232856e37c7cf9a9672958dff93b6d821896f6dbcbd44953043254acf28407c6e4cfba62d5fa8bf38142fd08 languageName: node linkType: hard -"@shikijs/types@npm:3.4.0, @shikijs/types@npm:^3.4.0": - version: 3.4.0 - resolution: "@shikijs/types@npm:3.4.0" +"@shikijs/types@npm:3.7.0, @shikijs/types@npm:^3.7.0": + version: 3.7.0 + resolution: "@shikijs/types@npm:3.7.0" dependencies: "@shikijs/vscode-textmate": "npm:^10.0.2" "@types/hast": "npm:^3.0.4" - checksum: 10/bca759ac0972f9ab673b199d44fb4655eb75a1af68b024f05126ff6ef0ce1fd7d316ca16da8eb7c383de8b058f358f90e6172be3783a1f04a3871f518fb0fd72 + checksum: 10/f6f4c6166968a24620b390bc4dc7d2238f8cbcb209d0b55583dafe0fea2de742479795b2bdede2b3f070159550b2e36519d3933ac9f23ca02e036c87fed74db4 languageName: node linkType: hard @@ -19417,17 +19304,6 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-themes@npm:^8.6.12": - version: 8.6.12 - resolution: "@storybook/addon-themes@npm:8.6.12" - dependencies: - ts-dedent: "npm:^2.0.0" - peerDependencies: - storybook: ^8.6.12 - checksum: 10/2df945accd7c0546785f71e2adc4ed68d71a057bc54aaef53f16ce8fcbc5a494380d60f9dd58520fe7d93b021a1b09e3d73553766d4bf2a1d07a3d731132b939 - languageName: node - linkType: hard - "@storybook/addon-toolbars@npm:8.6.12": version: 8.6.12 resolution: "@storybook/addon-toolbars@npm:8.6.12" @@ -20807,7 +20683,7 @@ __metadata: languageName: node linkType: hard -"@tokenizer/inflate@npm:^0.2.6": +"@tokenizer/inflate@npm:^0.2.7": version: 0.2.7 resolution: "@tokenizer/inflate@npm:0.2.7" dependencies: @@ -20881,6 +20757,41 @@ __metadata: languageName: node linkType: hard +"@ts-graphviz/adapter@npm:^2.0.6": + version: 2.0.6 + resolution: "@ts-graphviz/adapter@npm:2.0.6" + dependencies: + "@ts-graphviz/common": "npm:^2.1.5" + checksum: 10/6f15c14a166126e29dddb13f2ad012d8ac4d883e6fa789263b05ee50e0b47f2c09cf4c7f09b549e711563c30d6a6c2e45b52df0fd2701db2953dff112c0e9ea6 + languageName: node + linkType: hard + +"@ts-graphviz/ast@npm:^2.0.7": + version: 2.0.7 + resolution: "@ts-graphviz/ast@npm:2.0.7" + dependencies: + "@ts-graphviz/common": "npm:^2.1.5" + checksum: 10/ca2e0054cb97106e5993d642b8277b60b29a1d227ff75e576d56704a8364790d3fb535788243ac2ec7bc46f077cd760da61fa4a76ddfda5877d40d77b857c3c5 + languageName: node + linkType: hard + +"@ts-graphviz/common@npm:^2.1.5": + version: 2.1.5 + resolution: "@ts-graphviz/common@npm:2.1.5" + checksum: 10/421ea1a0d32917d6f26bceaf7b8e99db9f405afd3bbbb83bb9d2c759ee4bdcf15d5e611b3590becf55615f0ff35a9766fb19268c8c01c3dee0b02a74d0ef1a27 + languageName: node + linkType: hard + +"@ts-graphviz/core@npm:^2.0.7": + version: 2.0.7 + resolution: "@ts-graphviz/core@npm:2.0.7" + dependencies: + "@ts-graphviz/ast": "npm:^2.0.7" + "@ts-graphviz/common": "npm:^2.1.5" + checksum: 10/a2884db12a822ba0fa22845d382459332add43b8297c78d6e7223d89403aacf83508133a00bbf2122c6097b52351bfc5bcf856539379c6d35c9f1439d39cb89b + languageName: node + linkType: hard + "@ts-morph/common@npm:~0.25.0": version: 0.25.0 resolution: "@ts-morph/common@npm:0.25.0" @@ -20969,10 +20880,10 @@ __metadata: languageName: node linkType: hard -"@types/aws-lambda@npm:8.10.143, @types/aws-lambda@npm:^8.10.83": - version: 8.10.143 - resolution: "@types/aws-lambda@npm:8.10.143" - checksum: 10/326a6af5f26e6abab5ec0479829998714280656ea4f9e8623d1f18b159db7993116acbe2e5b0351e8e34601ff283c79b2e8c7c8c0c874f43d2649d9b00c50942 +"@types/aws-lambda@npm:8.10.150, @types/aws-lambda@npm:^8.10.83": + version: 8.10.150 + resolution: "@types/aws-lambda@npm:8.10.150" + checksum: 10/d837ae0b94fb16c7cfec3711126f0e7fb109fc3e6d14d994d083d2039c4f2bc52a75f256ee31a8010f023ce78ddcf3746ad43d552592a0f56720167f6d3111be languageName: node linkType: hard @@ -21061,12 +20972,12 @@ __metadata: languageName: node linkType: hard -"@types/bunyan@npm:1.8.9": - version: 1.8.9 - resolution: "@types/bunyan@npm:1.8.9" +"@types/bunyan@npm:1.8.11": + version: 1.8.11 + resolution: "@types/bunyan@npm:1.8.11" dependencies: "@types/node": "npm:*" - checksum: 10/5d6e818cc324eee60ad4658fc169bad2a7ec794de383de5333327951c7be74804cf70230ac4a93b4e6ce5d86106e81e6fcc8c617454617bad6a721011b619435 + checksum: 10/8906ec6c0573f563139681344c2a1d220c394e4aa5b88ff99b011894734f74aafc9d0b3a71758dda3b0ee30e9b6370a8aa48ac26b5585f3c8d7e0fe8db6ca844 languageName: node linkType: hard @@ -21169,12 +21080,12 @@ __metadata: languageName: node linkType: hard -"@types/connect@npm:*, @types/connect@npm:3.4.36": - version: 3.4.36 - resolution: "@types/connect@npm:3.4.36" +"@types/connect@npm:*, @types/connect@npm:3.4.38": + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" dependencies: "@types/node": "npm:*" - checksum: 10/4dee3d966fb527b98f0cbbdcf6977c9193fc3204ed539b7522fe5e64dfa45f9017bdda4ffb1f760062262fce7701a0ee1c2f6ce2e50af36c74d4e37052303172 + checksum: 10/7eb1bc5342a9604facd57598a6c62621e244822442976c443efb84ff745246b10d06e8b309b6e80130026a396f19bf6793b7cecd7380169f369dac3bfc46fb99 languageName: node linkType: hard @@ -21769,9 +21680,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.151": - version: 4.17.18 - resolution: "@types/lodash@npm:4.17.18" - checksum: 10/54ebb15b29925112dbe9da3abd99fb80d7202bc5ba20fc1b4fc8ea835d0012f00cbd9a3e7f367b70e7c3f2d5ee635964e3920a489625647b558f02994b3dd381 + version: 4.17.20 + resolution: "@types/lodash@npm:4.17.20" + checksum: 10/8cd8ad3bd78d2e06a93ae8d6c9907981d5673655fec7cb274a4d9a59549aab5bb5b3017361280773b8990ddfccf363e14d1b37c97af8a9fe363de677f9a61524 languageName: node linkType: hard @@ -21895,12 +21806,12 @@ __metadata: languageName: node linkType: hard -"@types/mysql@npm:2.15.26": - version: 2.15.26 - resolution: "@types/mysql@npm:2.15.26" +"@types/mysql@npm:2.15.27": + version: 2.15.27 + resolution: "@types/mysql@npm:2.15.27" dependencies: "@types/node": "npm:*" - checksum: 10/8f205eeaca8f94e998ce4707354bfd02b6ca0da5b7c22289f8f6ff864d549bfb95ca7ddc2f2ebe69eb8f7e3d1f5d8a5b9a2f98aee13824dbc48051bf53a1664d + checksum: 10/a8c743501036f494bb8b26ee04ce914c9cce88955d9ba48ff77d2b5b1bc403d4d99804dbf02238c1491fa93e2242983b1492ad8c2b39755dabd68683dada9e8f languageName: node linkType: hard @@ -22020,6 +21931,15 @@ __metadata: languageName: node linkType: hard +"@types/oracledb@npm:6.5.2": + version: 6.5.2 + resolution: "@types/oracledb@npm:6.5.2" + dependencies: + "@types/node": "npm:*" + checksum: 10/de4537f1718a03401d2726afb289cb9d3e421645b9024001458e8be626d6cdc01328c2c89f74c345e180506b334057915252221b15b253dcb0a60f337b5715fc + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.0 resolution: "@types/parse-json@npm:4.0.0" @@ -22104,25 +22024,14 @@ __metadata: languageName: node linkType: hard -"@types/pg@npm:*": - version: 8.11.10 - resolution: "@types/pg@npm:8.11.10" - dependencies: - "@types/node": "npm:*" - pg-protocol: "npm:*" - pg-types: "npm:^4.0.1" - checksum: 10/65b7d7ca9c90b7cb94aa94ad94bb1883356845e1f64688bc824ecd499da25f63a2400f0a58500554637048a7cc8b91055bbfe14301c082ce9669afd0c18e414c - languageName: node - linkType: hard - -"@types/pg@npm:8.6.1": - version: 8.6.1 - resolution: "@types/pg@npm:8.6.1" +"@types/pg@npm:*, @types/pg@npm:8.15.4": + version: 8.15.4 + resolution: "@types/pg@npm:8.15.4" dependencies: "@types/node": "npm:*" pg-protocol: "npm:*" pg-types: "npm:^2.2.0" - checksum: 10/bf1134ea194ad9cb8bfe0aab7a532713c63bae1d95909fa45e8dc1945e44ede74f2d4c5b2cd2f9712c6b970896929e0d82480f9c9da79addf405c089b590e562 + checksum: 10/dd9203ae6732acad4892513fc99eb2bc699935a95b62e9fdbdcc6d1a90f63881b5fd89d4cac1729790ab3d0bb7c64130b144c65abef34e6bbed063ff43a739a6 languageName: node linkType: hard @@ -22171,9 +22080,9 @@ __metadata: linkType: hard "@types/qs@npm:*, @types/qs@npm:^6.9.6": - version: 6.9.18 - resolution: "@types/qs@npm:6.9.18" - checksum: 10/152fab96efd819cc82ae67c39f089df415da6deddb48f1680edaaaa4e86a2a597de7b2ff0ad391df66d11a07006a08d52c9405e86b8cb8f3d5ba15881fe56cc7 + version: 6.14.0 + resolution: "@types/qs@npm:6.14.0" + checksum: 10/1909205514d22b3cbc7c2314e2bd8056d5f05dfb21cf4377f0730ee5e338ea19957c41735d5e4806c746176563f50005bbab602d8358432e25d900bdf4970826 languageName: node linkType: hard @@ -22259,15 +22168,6 @@ __metadata: languageName: node linkType: hard -"@types/react-text-truncate@npm:^0.14.0": - version: 0.14.4 - resolution: "@types/react-text-truncate@npm:0.14.4" - dependencies: - "@types/react": "npm:*" - checksum: 10/bbefba6aebb607fd0c5121b587f9604cd7c8a0b676666f85cbd8e6c64d17e72f633288601386b82cc97227d39e0a4e8b37de437e524295520641a4873fa1bff5 - languageName: node - linkType: hard - "@types/react-transition-group@npm:^4.2.0, @types/react-transition-group@npm:^4.4.10": version: 4.4.10 resolution: "@types/react-transition-group@npm:4.4.10" @@ -22835,6 +22735,19 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/project-service@npm:8.35.0": + version: 8.35.0 + resolution: "@typescript-eslint/project-service@npm:8.35.0" + dependencies: + "@typescript-eslint/tsconfig-utils": "npm:^8.35.0" + "@typescript-eslint/types": "npm:^8.35.0" + debug: "npm:^4.3.4" + peerDependencies: + typescript: ">=4.8.4 <5.9.0" + checksum: 10/a9419da92231aa27f75078fcffab1d02398b50fdb7d5399775a414ba02570682b4b60cdfafb544a021b0dc2372f029c4195f5ae17c50deb11c25661b2ac18a74 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/scope-manager@npm:5.62.0" @@ -22865,6 +22778,15 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/tsconfig-utils@npm:8.35.0, @typescript-eslint/tsconfig-utils@npm:^8.35.0": + version: 8.35.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.35.0" + peerDependencies: + typescript: ">=4.8.4 <5.9.0" + checksum: 10/4160928313ccbe8b169a009b9c1220826c7df7aab427f960c31f3b838931bc7a121ebee8040118481e4528e2e3cf1b26da047c6ac1d802ecff2ef7206026ea6b + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.29.1": version: 8.29.1 resolution: "@typescript-eslint/type-utils@npm:8.29.1" @@ -22901,6 +22823,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.35.0, @typescript-eslint/types@npm:^8.35.0": + version: 8.35.0 + resolution: "@typescript-eslint/types@npm:8.35.0" + checksum: 10/34b5e6da2c59ea84cd528608fff0cc14b102fd23f5517dfee4ef38c9372861d80b5bf92445c9679674f0a4f8dc4ded5066c1bca2bc5569c47515f94568984f35 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" @@ -22956,6 +22885,26 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:^8.23.0": + version: 8.35.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.35.0" + dependencies: + "@typescript-eslint/project-service": "npm:8.35.0" + "@typescript-eslint/tsconfig-utils": "npm:8.35.0" + "@typescript-eslint/types": "npm:8.35.0" + "@typescript-eslint/visitor-keys": "npm:8.35.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + typescript: ">=4.8.4 <5.9.0" + checksum: 10/4dff7c5a8853c8f4e30d35565c62d3ad5bf8445309bd465d94e9bca725853012bb9f58896a04207c30e10b6669511caac8c0f080ed781c93a3db81d5808195aa + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:8.29.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.8.1": version: 8.29.1 resolution: "@typescript-eslint/utils@npm:8.29.1" @@ -23033,6 +22982,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.35.0": + version: 8.35.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.35.0" + dependencies: + "@typescript-eslint/types": "npm:8.35.0" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10/c0acb13aac3a2be5e82844f7d2e86137347efdd04661dbf9fa69ef04a19dd2f1eb2f1eb6bfbfbaada78a46884308d2c0e0b5d0d1a094c84f2dfb670b67ac2b3b + languageName: node + linkType: hard + "@uiw/codemirror-extensions-basic-setup@npm:4.23.7": version: 4.23.7 resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.23.7" @@ -23401,6 +23360,63 @@ __metadata: languageName: node linkType: hard +"@vue/compiler-core@npm:3.5.17": + version: 3.5.17 + resolution: "@vue/compiler-core@npm:3.5.17" + dependencies: + "@babel/parser": "npm:^7.27.5" + "@vue/shared": "npm:3.5.17" + entities: "npm:^4.5.0" + estree-walker: "npm:^2.0.2" + source-map-js: "npm:^1.2.1" + checksum: 10/b7900f0498cc1f0496e003e0e783ae09ad3fde25258ac635372b704533a14105a04d690b97d196ded5f2cf04ced078a59a53533242acfdaa4508432296372f54 + languageName: node + linkType: hard + +"@vue/compiler-dom@npm:3.5.17": + version: 3.5.17 + resolution: "@vue/compiler-dom@npm:3.5.17" + dependencies: + "@vue/compiler-core": "npm:3.5.17" + "@vue/shared": "npm:3.5.17" + checksum: 10/4370ce4c31c578ec864e25eddbeac23b9498036912a82ba26545346dde4cfc378624bda2865db5104fd6a57321de6f527525af77cd5f83f7d1cd67b00bf1c6de + languageName: node + linkType: hard + +"@vue/compiler-sfc@npm:^3.5.13": + version: 3.5.17 + resolution: "@vue/compiler-sfc@npm:3.5.17" + dependencies: + "@babel/parser": "npm:^7.27.5" + "@vue/compiler-core": "npm:3.5.17" + "@vue/compiler-dom": "npm:3.5.17" + "@vue/compiler-ssr": "npm:3.5.17" + "@vue/shared": "npm:3.5.17" + estree-walker: "npm:^2.0.2" + magic-string: "npm:^0.30.17" + postcss: "npm:^8.5.6" + source-map-js: "npm:^1.2.1" + checksum: 10/32a0e611615e1a9f553a3744084d15b388a48ec4218d1159ab5bf57897e38779fe408fc4e63ed43c134134e301d6a32a812f4e3f58a9c7e0fddba9d96f86a537 + languageName: node + linkType: hard + +"@vue/compiler-ssr@npm:3.5.17": + version: 3.5.17 + resolution: "@vue/compiler-ssr@npm:3.5.17" + dependencies: + "@vue/compiler-dom": "npm:3.5.17" + "@vue/shared": "npm:3.5.17" + checksum: 10/ed92e187d7fd29350c6a267a0ca8989f626b1b90e46ab2dbf9492a7164c4b32a7fd7fb5001dd43de0200c5f4cd3b3152d5cd4f55e39fe6f9837a30ce944876b1 + languageName: node + linkType: hard + +"@vue/shared@npm:3.5.17": + version: 3.5.17 + resolution: "@vue/shared@npm:3.5.17" + checksum: 10/d33b7435df4af16586679e713a0c15abb8c79a49067f558cbea6645d69f64ee2fd5b669a834abce2a084cb24a0d35a4a20164ba54625fbab70b3cc06b6913f72 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.12.1, @webassemblyjs/ast@npm:^1.12.1": version: 1.12.1 resolution: "@webassemblyjs/ast@npm:1.12.1" @@ -24856,6 +24872,13 @@ __metadata: languageName: node linkType: hard +"app-module-path@npm:^2.2.0": + version: 2.2.0 + resolution: "app-module-path@npm:2.2.0" + checksum: 10/9ed8c6ce6247a6b5d556039f29b4610869237bbb5b8f3d905b22bd2d314c30efcc0fb70c2626d7461ecc52ec7edec9908f660d0938d2bea5b8cfc6868a28806f + languageName: node + linkType: hard + "app-next-example-plugin@workspace:packages/app-next-example-plugin": version: 0.0.0-use.local resolution: "app-next-example-plugin@workspace:packages/app-next-example-plugin" @@ -25220,6 +25243,13 @@ __metadata: languageName: node linkType: hard +"ast-module-types@npm:^6.0.1": + version: 6.0.1 + resolution: "ast-module-types@npm:6.0.1" + checksum: 10/d3a2e0ae998470c7c3d92e2bb12dfcf2797bca17d2548f60b57ed34638d2278f5f99140df009ab3cd73dbe15885b660fe780fc1c14c249f5c50b15a6e014740c + languageName: node + linkType: hard + "ast-types-flow@npm:^0.0.8": version: 0.0.8 resolution: "ast-types-flow@npm:0.0.8" @@ -27284,7 +27314,7 @@ __metadata: languageName: node linkType: hard -"color-name@npm:^1.0.0, color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:^1.1.4, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 @@ -28578,16 +28608,6 @@ __metadata: languageName: node linkType: hard -"dagre@npm:^0.8.5": - version: 0.8.5 - resolution: "dagre@npm:0.8.5" - dependencies: - graphlib: "npm:^2.1.8" - lodash: "npm:^4.17.15" - checksum: 10/f39899e29e9090581d67177ef6e2dd3ca5d7f764fbf3de81758d879bba66fee6fd8802d41d0c5d3d9a0563b334e99e1454a8d6ab4ce17e8e4f50836a3a403fdd - languageName: node - linkType: hard - "damerau-levenshtein@npm:^1.0.8": version: 1.0.8 resolution: "damerau-levenshtein@npm:1.0.8" @@ -28604,6 +28624,13 @@ __metadata: languageName: node linkType: hard +"data-uri-to-buffer@npm:^4.0.0": + version: 4.0.1 + resolution: "data-uri-to-buffer@npm:4.0.1" + checksum: 10/0d0790b67ffec5302f204c2ccca4494f70b4e2d940fea3d36b09f0bb2b8539c2e86690429eb1f1dc4bcc9e4df0644193073e63d9ee48ac9fce79ec1506e4aa4c + languageName: node + linkType: hard + "data-uri-to-buffer@npm:^6.0.0": version: 6.0.1 resolution: "data-uri-to-buffer@npm:6.0.1" @@ -29017,6 +29044,20 @@ __metadata: languageName: node linkType: hard +"dependency-tree@npm:^11.0.0": + version: 11.2.0 + resolution: "dependency-tree@npm:11.2.0" + dependencies: + commander: "npm:^12.1.0" + filing-cabinet: "npm:^5.0.3" + precinct: "npm:^12.2.0" + typescript: "npm:^5.8.3" + bin: + dependency-tree: bin/cli.js + checksum: 10/0dac9f86f1587ce7c3b0050ce64a7f0f9b86dd5b1c318feadfa1d440a3abb1eaa9cd615fc151c41d17301509461669983fd311368cb7113124ad5df17ba850e7 + languageName: node + linkType: hard + "deprecation@npm:^2.0.0, deprecation@npm:^2.3.1": version: 2.3.1 resolution: "deprecation@npm:2.3.1" @@ -29119,6 +29160,108 @@ __metadata: languageName: node linkType: hard +"detective-amd@npm:^6.0.1": + version: 6.0.1 + resolution: "detective-amd@npm:6.0.1" + dependencies: + ast-module-types: "npm:^6.0.1" + escodegen: "npm:^2.1.0" + get-amd-module-type: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + bin: + detective-amd: bin/cli.js + checksum: 10/e709bd512933f33e1f461045f8ac10295661f4cca7cd226d5d69e6972a6392e4dd3879f6c9411e6f22a12c3fac499205492cbe842cc2423aa116d1887d34d167 + languageName: node + linkType: hard + +"detective-cjs@npm:^6.0.1": + version: 6.0.1 + resolution: "detective-cjs@npm:6.0.1" + dependencies: + ast-module-types: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + checksum: 10/8261af91c98178c2580d8d3bbfc394ccf3eb161c15c88e119dd7ce3a1ff24ccf37b2faee12f6da8efd860396bca89dca4e76530d39a26207d710da93131f5db7 + languageName: node + linkType: hard + +"detective-es6@npm:^5.0.1": + version: 5.0.1 + resolution: "detective-es6@npm:5.0.1" + dependencies: + node-source-walk: "npm:^7.0.1" + checksum: 10/460751524871a11cf7c39e12b4316f745fff68f9e5f5fd85193c3ff651cb34cdd51a34d187a713735eb407b53c706645643ad8fd2a2ca098d551ffffe98935b1 + languageName: node + linkType: hard + +"detective-postcss@npm:^7.0.1": + version: 7.0.1 + resolution: "detective-postcss@npm:7.0.1" + dependencies: + is-url: "npm:^1.2.4" + postcss-values-parser: "npm:^6.0.2" + peerDependencies: + postcss: ^8.4.47 + checksum: 10/5cbe1ecc224beb3aa846477de83959c349764b6b912decc92e4c0e1dc22641b5d97b6cdee54dfa2706c71bed50b363c87072314e22730a0c66f82f4be145221c + languageName: node + linkType: hard + +"detective-sass@npm:^6.0.1": + version: 6.0.1 + resolution: "detective-sass@npm:6.0.1" + dependencies: + gonzales-pe: "npm:^4.3.0" + node-source-walk: "npm:^7.0.1" + checksum: 10/bf941665aa8fbdf02399f227d8a80ca059e22d2a2f8d34e90ca06fe3e2772afd63b75dc267712ac8a7b6dc580a9be91a7f965b790803488544472b36dd904c72 + languageName: node + linkType: hard + +"detective-scss@npm:^5.0.1": + version: 5.0.1 + resolution: "detective-scss@npm:5.0.1" + dependencies: + gonzales-pe: "npm:^4.3.0" + node-source-walk: "npm:^7.0.1" + checksum: 10/f5ebb927fd789f8e069f186439c60e8b9efe1e27c45d755c8dd00fdab4a390e28ed0e896e5ecc4275d1dac0b4afa1b1cb7bedf08bdc2155c2f779b69c882705d + languageName: node + linkType: hard + +"detective-stylus@npm:^5.0.1": + version: 5.0.1 + resolution: "detective-stylus@npm:5.0.1" + checksum: 10/28c4168a82e427ba51b24a4d5ef6ad0fb55183dc57317073a45801ff3e2617a86c3288a4b6cd2c84911371128bd841681d855276215926bc1d176da4ebeb5ae2 + languageName: node + linkType: hard + +"detective-typescript@npm:^14.0.0": + version: 14.0.0 + resolution: "detective-typescript@npm:14.0.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:^8.23.0" + ast-module-types: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + peerDependencies: + typescript: ^5.4.4 + checksum: 10/8dcf16e6bdc9faf0318553f3a2e1e198782cf21edde264d29efd33d88551a79ff1fe3d2d1ef7b2c00a8a88da0323ead4fddbc7ed92270e425da42c4608bec97b + languageName: node + linkType: hard + +"detective-vue2@npm:^2.2.0": + version: 2.2.0 + resolution: "detective-vue2@npm:2.2.0" + dependencies: + "@dependents/detective-less": "npm:^5.0.1" + "@vue/compiler-sfc": "npm:^3.5.13" + detective-es6: "npm:^5.0.1" + detective-sass: "npm:^6.0.1" + detective-scss: "npm:^5.0.1" + detective-stylus: "npm:^5.0.1" + detective-typescript: "npm:^14.0.0" + peerDependencies: + typescript: ^5.4.4 + checksum: 10/896226e5993e7b87948db0aaca4d8980b015828e797a1e46ae102fa079abcbb9713ef170df65735a69644f2e2bf7eb4ee8c2036727b22a65616e1fb5823039ab + languageName: node + linkType: hard + "dezalgo@npm:^1.0.0, dezalgo@npm:^1.0.4": version: 1.0.4 resolution: "dezalgo@npm:1.0.4" @@ -30604,10 +30747,10 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^4.2.0": - version: 4.2.0 - resolution: "eslint-visitor-keys@npm:4.2.0" - checksum: 10/9651b3356b01760e586b4c631c5268c0e1a85236e3292bf754f0472f465bf9a856c0ddc261fceace155334118c0151778effafbab981413dbf9288349343fa25 +"eslint-visitor-keys@npm:^4.2.0, eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10/3ee00fc6a7002d4b0ffd9dc99e13a6a7882c557329e6c25ab254220d71e5c9c4f89dca4695352949ea678eb1f3ba912a18ef8aac0a7fe094196fd92f441bfce2 languageName: node linkType: hard @@ -30880,7 +31023,6 @@ __metadata: resolution: "example-app-next@workspace:packages/app-next" dependencies: "@backstage/app-defaults": "workspace:^" - "@backstage/canon": "workspace:^" "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -30920,6 +31062,7 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@backstage/ui": "workspace:^" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -30954,7 +31097,6 @@ __metadata: resolution: "example-app@workspace:packages/app" dependencies: "@backstage/app-defaults": "workspace:^" - "@backstage/canon": "workspace:^" "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -30990,6 +31132,7 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@backstage/ui": "workspace:^" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -31055,7 +31198,7 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-signals-backend": "workspace:^" "@backstage/plugin-techdocs-backend": "workspace:^" - "@opentelemetry/auto-instrumentations-node": "npm:^0.54.0" + "@opentelemetry/auto-instrumentations-node": "npm:^0.61.0" "@opentelemetry/exporter-prometheus": "npm:^0.54.0" "@opentelemetry/sdk-node": "npm:^0.54.0" example-app: "link:../app" @@ -31595,6 +31738,16 @@ __metadata: languageName: node linkType: hard +"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": + version: 3.2.0 + resolution: "fetch-blob@npm:3.2.0" + dependencies: + node-domexception: "npm:^1.0.0" + web-streams-polyfill: "npm:^3.0.3" + checksum: 10/5264ecceb5fdc19eb51d1d0359921f12730941e333019e673e71eb73921146dceabcb0b8f534582be4497312d656508a439ad0f5edeec2b29ab2e10c72a1f86b + languageName: node + linkType: hard + "fflate@npm:^0.8.2": version: 0.8.2 resolution: "fflate@npm:0.8.2" @@ -31620,15 +31773,15 @@ __metadata: languageName: node linkType: hard -"file-type@npm:20.5.0": - version: 20.5.0 - resolution: "file-type@npm:20.5.0" +"file-type@npm:21.0.0": + version: 21.0.0 + resolution: "file-type@npm:21.0.0" dependencies: - "@tokenizer/inflate": "npm:^0.2.6" - strtok3: "npm:^10.2.0" + "@tokenizer/inflate": "npm:^0.2.7" + strtok3: "npm:^10.2.2" token-types: "npm:^6.0.0" uint8array-extras: "npm:^1.4.0" - checksum: 10/1cc1ccd7cf76086e10b65cba88c708e0653676fbae900107deeb91c46de011acd1492200bf47e75cddf395de27dbe8584ca042f4cfa4a1efdf933644b7143f1d + checksum: 10/6980e8b0ef870a98b51ab2eac5db94a1884de8476fe49dc02d2f7e0c1d1d7d44d42b6c59e67867ae90f321ddf4edd00fcfda01821591e2fa05385d0e438a9dc1 languageName: node linkType: hard @@ -31673,6 +31826,27 @@ __metadata: languageName: node linkType: hard +"filing-cabinet@npm:^5.0.3": + version: 5.0.3 + resolution: "filing-cabinet@npm:5.0.3" + dependencies: + app-module-path: "npm:^2.2.0" + commander: "npm:^12.1.0" + enhanced-resolve: "npm:^5.18.0" + module-definition: "npm:^6.0.1" + module-lookup-amd: "npm:^9.0.3" + resolve: "npm:^1.22.10" + resolve-dependency-path: "npm:^4.0.1" + sass-lookup: "npm:^6.1.0" + stylus-lookup: "npm:^6.1.0" + tsconfig-paths: "npm:^4.2.0" + typescript: "npm:^5.7.3" + bin: + filing-cabinet: bin/cli.js + checksum: 10/0434ee0aa745c4da8f5e112563ee712a73c0582144ed3a37afad404cf42f700f7770ab7c0d00a9e062f14b5d52f9ab2b04e867f6f4b5c4bbde633242ee5020ac + languageName: node + linkType: hard + "fill-range@npm:^7.1.1": version: 7.1.1 resolution: "fill-range@npm:7.1.1" @@ -31790,15 +31964,15 @@ __metadata: linkType: hard "find-process@npm:^1.4.5": - version: 1.4.10 - resolution: "find-process@npm:1.4.10" + version: 1.4.11 + resolution: "find-process@npm:1.4.11" dependencies: chalk: "npm:~4.1.2" commander: "npm:^12.1.0" loglevel: "npm:^1.9.2" bin: find-process: bin/find-process.js - checksum: 10/cda45cfb3f52cbc7f643a465a8bffc19e2a3ac49ec5aa74e9b18ed2e4d6d62e370443d38c5fdd3de6b30b232fda51db1d74c2574d70d28e6c896d49df3bc3bcd + checksum: 10/95f7106877c86fc09804b29339cfac518a43228c1b5f4a4e9442e57ac5538369fbeafb746fa96390ecd7be6f5a9119b58c952b5c96a0cb9f2490ef19298dec1e languageName: node linkType: hard @@ -32091,6 +32265,15 @@ __metadata: languageName: node linkType: hard +"formdata-polyfill@npm:^4.0.10": + version: 4.0.10 + resolution: "formdata-polyfill@npm:4.0.10" + dependencies: + fetch-blob: "npm:^3.1.2" + checksum: 10/9b5001d2edef3c9449ac3f48bd4f8cc92e7d0f2e7c1a5c8ba555ad4e77535cc5cf621fabe49e97f304067037282dd9093b9160a3cb533e46420b446c4e6bc06f + languageName: node + linkType: hard + "formidable@npm:^3.5.4": version: 3.5.4 resolution: "formidable@npm:3.5.4" @@ -32116,6 +32299,28 @@ __metadata: languageName: node linkType: hard +"framer-motion@npm:^12.20.1": + version: 12.20.1 + resolution: "framer-motion@npm:12.20.1" + dependencies: + motion-dom: "npm:^12.20.1" + motion-utils: "npm:^12.19.0" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10/ba36e76dbf66c856f0c5d3cfb80973bb0ef95ca9169fc16b22560a7bc55fbedcf63205266dba7beecac5152c4cd140097ff504c5d529beffca86cd85f97bf5e3 + languageName: node + linkType: hard + "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -32379,7 +32584,7 @@ __metadata: languageName: node linkType: hard -"gaxios@npm:^6.0.0, gaxios@npm:^6.0.2, gaxios@npm:^6.0.3, gaxios@npm:^6.1.1": +"gaxios@npm:^6.0.0, gaxios@npm:^6.0.2, gaxios@npm:^6.1.1": version: 6.7.1 resolution: "gaxios@npm:6.7.1" dependencies: @@ -32392,6 +32597,17 @@ __metadata: languageName: node linkType: hard +"gaxios@npm:^7.0.0, gaxios@npm:^7.0.0-rc.4": + version: 7.1.1 + resolution: "gaxios@npm:7.1.1" + dependencies: + extend: "npm:^3.0.2" + https-proxy-agent: "npm:^7.0.1" + node-fetch: "npm:^3.3.2" + checksum: 10/9e5fa8b458c318a95d4dff0f6ac187a1b8933fb1de5b376b7098b27dfc5bf6025b62c87ed20bdae0496ae73a279834bc6b974c28849a674deed0089f2ba57b98 + languageName: node + linkType: hard + "gcp-metadata@npm:^6.0.0, gcp-metadata@npm:^6.1.0": version: 6.1.0 resolution: "gcp-metadata@npm:6.1.0" @@ -32402,6 +32618,17 @@ __metadata: languageName: node linkType: hard +"gcp-metadata@npm:^7.0.0": + version: 7.0.1 + resolution: "gcp-metadata@npm:7.0.1" + dependencies: + gaxios: "npm:^7.0.0" + google-logging-utils: "npm:^1.0.0" + json-bigint: "npm:^1.0.0" + checksum: 10/c82f20a4ce22278998fe033e668a66bff04d2b3e95e19f968adeac829e12274e07b453fcfcf34573a6d702b3570c5556cba6eb6b59d1c03757c866e3271972c1 + languageName: node + linkType: hard + "generate-function@npm:^2.3.1": version: 2.3.1 resolution: "generate-function@npm:2.3.1" @@ -32434,6 +32661,16 @@ __metadata: languageName: node linkType: hard +"get-amd-module-type@npm:^6.0.1": + version: 6.0.1 + resolution: "get-amd-module-type@npm:6.0.1" + dependencies: + ast-module-types: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + checksum: 10/775e60d53f3c0aa4747c98ae2055957b688ffcd47944bc6d8af8ab7c1ab0b337e3d4a5624f29d815fe91e3da1830b8f9bad07d0da7025368e6e144205712b536 + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -32473,6 +32710,13 @@ __metadata: languageName: node linkType: hard +"get-own-enumerable-property-symbols@npm:^3.0.0": + version: 3.0.2 + resolution: "get-own-enumerable-property-symbols@npm:3.0.2" + checksum: 10/8f0331f14159f939830884799f937343c8c0a2c330506094bc12cbee3665d88337fe97a4ea35c002cc2bdba0f5d9975ad7ec3abb925015cdf2a93e76d4759ede + languageName: node + linkType: hard + "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" @@ -32670,15 +32914,19 @@ __metadata: languageName: node linkType: hard -"glob@npm:9.3.5": - version: 9.3.5 - resolution: "glob@npm:9.3.5" +"glob@npm:11.0.3, glob@npm:^11.0.1": + version: 11.0.3 + resolution: "glob@npm:11.0.3" dependencies: - fs.realpath: "npm:^1.0.0" - minimatch: "npm:^8.0.2" - minipass: "npm:^4.2.4" - path-scurry: "npm:^1.6.1" - checksum: 10/e5fa8a58adf53525bca42d82a1fad9e6800032b7e4d372209b80cfdca524dd9a7dbe7d01a92d7ed20d89c572457f12c250092bc8817cb4f1c63efefdf9b658c0 + foreground-child: "npm:^3.3.1" + jackspeak: "npm:^4.1.1" + minimatch: "npm:^10.0.3" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^2.0.0" + bin: + glob: dist/esm/bin.mjs + checksum: 10/2ae536c1360c0266b523b2bfa6aadc10144a8b7e08869b088e37ac3c27cd30774f82e4bfb291cde796776e878f9e13200c7ff44010eb7054e00f46f649397893 languageName: node linkType: hard @@ -32698,23 +32946,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^11.0.1": - version: 11.0.3 - resolution: "glob@npm:11.0.3" - dependencies: - foreground-child: "npm:^3.3.1" - jackspeak: "npm:^4.1.1" - minimatch: "npm:^10.0.3" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^2.0.0" - bin: - glob: dist/esm/bin.mjs - checksum: 10/2ae536c1360c0266b523b2bfa6aadc10144a8b7e08869b088e37ac3c27cd30774f82e4bfb291cde796776e878f9e13200c7ff44010eb7054e00f46f649397893 - languageName: node - linkType: hard - -"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7": +"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.3": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -32883,6 +33115,17 @@ __metadata: languageName: node linkType: hard +"gonzales-pe@npm:^4.3.0": + version: 4.3.0 + resolution: "gonzales-pe@npm:4.3.0" + dependencies: + minimist: "npm:^1.2.5" + bin: + gonzales: bin/gonzales.js + checksum: 10/d1676546bcaa4cb1c6c1fc5de5d62e85960665a13a4c489b02baeb58a10c53a249beef05ceaf21ea801813a559ff17d7b61158aa417211c135bcb8bdcb1701ca + languageName: node + linkType: hard + "goober@npm:^2.0.33": version: 2.1.14 resolution: "goober@npm:2.1.14" @@ -32892,7 +33135,22 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.2.0, google-auth-library@npm:^9.3.0, google-auth-library@npm:^9.6.3, google-auth-library@npm:^9.7.0": +"google-auth-library@npm:^10.0.0, google-auth-library@npm:^10.0.0-rc.1": + version: 10.1.0 + resolution: "google-auth-library@npm:10.1.0" + dependencies: + base64-js: "npm:^1.3.0" + ecdsa-sig-formatter: "npm:^1.0.11" + gaxios: "npm:^7.0.0" + gcp-metadata: "npm:^7.0.0" + google-logging-utils: "npm:^1.0.0" + gtoken: "npm:^8.0.0" + jws: "npm:^4.0.0" + checksum: 10/f3e2130d38fe12045dd20480b4ea5f78a6a058d918e56d4332858c287f9b010b6aca312058b9c032843396da0fbaded6e5475866895eed461c7a06e2dd646b61 + languageName: node + linkType: hard + +"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.3.0, google-auth-library@npm:^9.6.3": version: 9.15.1 resolution: "google-auth-library@npm:9.15.1" dependencies: @@ -32926,6 +33184,13 @@ __metadata: languageName: node linkType: hard +"google-logging-utils@npm:^1.0.0": + version: 1.1.1 + resolution: "google-logging-utils@npm:1.1.1" + checksum: 10/51f915d97a812af9edeccf24d43bbec5f4d98dab4f874a08083e847d495fc94185d309f21ae7f590c9f7951bc25bc3095fa4ae73113aba47e86482f69860a806 + languageName: node + linkType: hard + "google-protobuf@npm:^3.15.8, google-protobuf@npm:^3.21.2": version: 3.21.2 resolution: "google-protobuf@npm:3.21.2" @@ -32933,17 +33198,16 @@ __metadata: languageName: node linkType: hard -"googleapis-common@npm:^7.0.0": - version: 7.2.0 - resolution: "googleapis-common@npm:7.2.0" +"googleapis-common@npm:^8.0.2-rc.0": + version: 8.0.2-rc.0 + resolution: "googleapis-common@npm:8.0.2-rc.0" dependencies: extend: "npm:^3.0.2" - gaxios: "npm:^6.0.3" - google-auth-library: "npm:^9.7.0" + gaxios: "npm:^7.0.0-rc.4" + google-auth-library: "npm:^10.0.0-rc.1" qs: "npm:^6.7.0" url-template: "npm:^2.0.8" - uuid: "npm:^9.0.0" - checksum: 10/4b914be6681f2a5a02bd0954a4a5cee1725d8623cb9d0a7c2fd7132de110e8d5707566cba39784e58147be39e74bc5513ad30fdcdaa6edcbb47ecf687003cb6c + checksum: 10/f630e8f37b2baa4980e3a66fb7736caa2a47f1f915bc6082ef844aa24be776ad2fbff39631346dcccc01c99dd5707fca02c786c6ba23ae459bcb23b125b4fb63 languageName: node linkType: hard @@ -33029,15 +33293,6 @@ __metadata: languageName: node linkType: hard -"graphlib@npm:^2.1.8": - version: 2.1.8 - resolution: "graphlib@npm:2.1.8" - dependencies: - lodash: "npm:^4.17.15" - checksum: 10/37cbd851d3c1fb99f3174750ccaa22305d23d11746e5df81a38ba3bf25c0ba29cd9658ba69a0159ea81d56c28e8e875033eeaaa7167d838419fae08d9cd2c62c - languageName: node - linkType: hard - "graphql-config@npm:^5.0.2": version: 5.1.5 resolution: "graphql-config@npm:5.1.5" @@ -33173,6 +33428,16 @@ __metadata: languageName: node linkType: hard +"gtoken@npm:^8.0.0": + version: 8.0.0 + resolution: "gtoken@npm:8.0.0" + dependencies: + gaxios: "npm:^7.0.0" + jws: "npm:^4.0.0" + checksum: 10/b921430395dcd06ee63c3fc5a5e339ca4d6dcb38b6d618beb0f260bae1088d53d130f86029a9d578f1601c64685f49a65dba57bbd617c4b14039180b67b6c5ce + languageName: node + linkType: hard + "gzip-size@npm:^6.0.0": version: 6.0.0 resolution: "gzip-size@npm:6.0.0" @@ -34735,6 +35000,13 @@ __metadata: languageName: node linkType: hard +"is-obj@npm:^1.0.1": + version: 1.0.1 + resolution: "is-obj@npm:1.0.1" + checksum: 10/3ccf0efdea12951e0b9c784e2b00e77e87b2f8bd30b42a498548a8afcc11b3287342a2030c308e473e93a7a19c9ea7854c99a8832a476591c727df2a9c79796c + languageName: node + linkType: hard + "is-obj@npm:^2.0.0": version: 2.0.0 resolution: "is-obj@npm:2.0.0" @@ -34856,6 +35128,13 @@ __metadata: languageName: node linkType: hard +"is-regexp@npm:^1.0.0": + version: 1.0.0 + resolution: "is-regexp@npm:1.0.0" + checksum: 10/be692828e24cba479ec33644326fa98959ec68ba77965e0291088c1a741feaea4919d79f8031708f85fd25e39de002b4520622b55460660b9c369e6f7187faef + languageName: node + linkType: hard + "is-resolvable@npm:^1.1.0": version: 1.1.0 resolution: "is-resolvable@npm:1.1.0" @@ -34992,6 +35271,13 @@ __metadata: languageName: node linkType: hard +"is-url-superb@npm:^4.0.0": + version: 4.0.0 + resolution: "is-url-superb@npm:4.0.0" + checksum: 10/fd55e91c96349acb0d688f95fcb1ac67450e5db934976e3a8ff13ef446841e779a6f4d18b15f02331f05a3429c8fdaba2382ac1ab444059e86e9ffcde1ec8db0 + languageName: node + linkType: hard + "is-url@npm:^1.2.4": version: 1.2.4 resolution: "is-url@npm:1.2.4" @@ -37896,6 +38182,33 @@ __metadata: languageName: node linkType: hard +"madge@npm:^8.0.0": + version: 8.0.0 + resolution: "madge@npm:8.0.0" + dependencies: + chalk: "npm:^4.1.2" + commander: "npm:^7.2.0" + commondir: "npm:^1.0.1" + debug: "npm:^4.3.4" + dependency-tree: "npm:^11.0.0" + ora: "npm:^5.4.1" + pluralize: "npm:^8.0.0" + pretty-ms: "npm:^7.0.1" + rc: "npm:^1.2.8" + stream-to-array: "npm:^2.3.0" + ts-graphviz: "npm:^2.1.2" + walkdir: "npm:^0.4.1" + peerDependencies: + typescript: ^5.4.4 + peerDependenciesMeta: + typescript: + optional: true + bin: + madge: bin/cli.js + checksum: 10/9adee480224aadb1d24d36f583396053c3cea84359316b601f5bc423c67c87e81ba842425acaa6c764ccc8c00241e2e78700b16f9af546111d1106b70c336174 + languageName: node + linkType: hard + "magic-string@npm:^0.25.7": version: 0.25.7 resolution: "magic-string@npm:0.25.7" @@ -37905,12 +38218,12 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.10, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": - version: 0.30.14 - resolution: "magic-string@npm:0.30.14" +"magic-string@npm:^0.30.10, magic-string@npm:^0.30.17, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": + version: 0.30.17 + resolution: "magic-string@npm:0.30.17" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.5.0" - checksum: 10/8ca0f8937c2824e48ebc70e7e065a193c467713639cc6e5972aaba0fa5417b375a6f62c383410a19a66e618c386bb7253fbd3ccbfb0144bb310f0ba772121f12 + checksum: 10/2f71af2b0afd78c2e9012a29b066d2c8ba45a9cd0c8070f7fd72de982fb1c403b4e3afdb1dae00691d56885ede66b772ef6bedf765e02e3a7066208fe2fec4aa languageName: node linkType: hard @@ -39069,15 +39382,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^8.0.2": - version: 8.0.4 - resolution: "minimatch@npm:8.0.4" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/aef05598ee565e1013bc8a10f53410ac681561f901c1a084b8ecfd016c9ed919f58f4bbd5b63e05643189dfb26e8106a84f0e1ff12e4a263aa37e1cae7ce9828 - languageName: node - linkType: hard - "minimatch@npm:^9.0.0, minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -39236,7 +39540,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^4.0.0, minipass@npm:^4.2.4": +"minipass@npm:^4.0.0": version: 4.2.8 resolution: "minipass@npm:4.2.8" checksum: 10/e148eb6dcb85c980234cad889139ef8ddf9d5bdac534f4f0268446c8792dd4c74f4502479be48de3c1cce2f6450f6da4d0d4a86405a8a12be04c1c36b339569a @@ -39432,6 +39736,18 @@ __metadata: languageName: node linkType: hard +"module-definition@npm:^6.0.1": + version: 6.0.1 + resolution: "module-definition@npm:6.0.1" + dependencies: + ast-module-types: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + bin: + module-definition: bin/cli.js + checksum: 10/a61280434289b9c2209a0075e3754731c797dce1816f164995e8a94ba57d3b0cffd6ca5d719b26cdef31c5fb41176676d54f2dc83cc62f7e61576369a05bef7c + languageName: node + linkType: hard + "module-details-from-path@npm:^1.0.3": version: 1.0.3 resolution: "module-details-from-path@npm:1.0.3" @@ -39439,6 +39755,20 @@ __metadata: languageName: node linkType: hard +"module-lookup-amd@npm:^9.0.3": + version: 9.0.5 + resolution: "module-lookup-amd@npm:9.0.5" + dependencies: + commander: "npm:^12.1.0" + glob: "npm:^7.2.3" + requirejs: "npm:^2.3.7" + requirejs-config-file: "npm:^4.0.0" + bin: + lookup-amd: bin/cli.js + checksum: 10/9d1e001a0d59a9169437eb595d26ccf6c0d2905ab46d26bf819495afdea3c796252c0417a4af62b42ce5ae519cc6d66968419a3c7b70b0671bc158a4bc57375a + languageName: node + linkType: hard + "moo@npm:^0.5.0": version: 0.5.2 resolution: "moo@npm:0.5.2" @@ -39459,6 +39789,43 @@ __metadata: languageName: node linkType: hard +"motion-dom@npm:^12.20.1": + version: 12.20.1 + resolution: "motion-dom@npm:12.20.1" + dependencies: + motion-utils: "npm:^12.19.0" + checksum: 10/b92d733fdfe3f66511f73c7f84f9483a0529eadf6ad2ab633cef584d161bcd1af786d257776e1fe7cd2b4e2c9c10912773f96ce9e2bd5b45c6c33ba6d9edfe86 + languageName: node + linkType: hard + +"motion-utils@npm:^12.19.0": + version: 12.19.0 + resolution: "motion-utils@npm:12.19.0" + checksum: 10/a6fe6b329bf4e2070bb95788218f36f0d7ea6cc3098e6ea2646ed68d5be88d25fa30e55284463ace78d19a5e19714875a7b70055bd86ae6e52a5fdee08438470 + languageName: node + linkType: hard + +"motion@npm:^12.20.1": + version: 12.20.1 + resolution: "motion@npm:12.20.1" + dependencies: + framer-motion: "npm:^12.20.1" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10/49057c8d5812207209ca078a67ee7467d2dca7abacdcf2db486cd28c3ca105a7fe2504c34407df201c85035f6df1c806954af94914417ee89d721133fc4e92ce + languageName: node + linkType: hard + "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4" @@ -39529,8 +39896,8 @@ __metadata: linkType: hard "msw@npm:^2.0.0, msw@npm:^2.0.8": - version: 2.10.2 - resolution: "msw@npm:2.10.2" + version: 2.10.4 + resolution: "msw@npm:2.10.4" dependencies: "@bundled-es-modules/cookie": "npm:^2.0.1" "@bundled-es-modules/statuses": "npm:^1.0.1" @@ -39557,7 +39924,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10/bc90bc34a0b9e978e662f33fa630a0de66c4b6eff3a92b41efa08bf67d79b43e4a961a17b0d274580393c912f4ac6226c76a8bc33148799b1ee43477df712c26 + checksum: 10/e2f25dda1aba66c7444c29c41d3157cb15c0332055ab7ebfb74ef4b506e7b90098cf37c577768edb5b2b2dbf0d6ed6a7a3ca8ee6da3d72df5a25823d82f33316 languageName: node linkType: hard @@ -39680,12 +40047,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.7": - version: 3.3.8 - resolution: "nanoid@npm:3.3.8" +"nanoid@npm:^3.3.11, nanoid@npm:^3.3.7": + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" bin: nanoid: bin/nanoid.cjs - checksum: 10/2d1766606cf0d6f47b6f0fdab91761bb81609b2e3d367027aff45e6ee7006f660fb7e7781f4a34799fe6734f1268eeed2e37a5fdee809ade0c2d4eb11b0f9c40 + checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48 languageName: node linkType: hard @@ -39928,6 +40295,17 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^3.3.2": + version: 3.3.2 + resolution: "node-fetch@npm:3.3.2" + dependencies: + data-uri-to-buffer: "npm:^4.0.0" + fetch-blob: "npm:^3.1.4" + formdata-polyfill: "npm:^4.0.10" + checksum: 10/24207ca8c81231c7c59151840e3fded461d67a31cf3e3b3968e12201a42f89ce4a0b5fb7079b1fa0a4655957b1ca9257553200f03a9f668b45ebad265ca5593d + languageName: node + linkType: hard + "node-forge@npm:^1, node-forge@npm:^1.2.1, node-forge@npm:^1.3.1": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -40093,6 +40471,15 @@ __metadata: languageName: node linkType: hard +"node-source-walk@npm:^7.0.1": + version: 7.0.1 + resolution: "node-source-walk@npm:7.0.1" + dependencies: + "@babel/parser": "npm:^7.26.7" + checksum: 10/cd71a136b095aa8055d2a670e7820d467eaad3c62d343dacb706d3ac651991ae73032ce5f82a9ac0373ec8186d98c3c7e9b4311f1cd0887d1ec035c734b5f5ed + languageName: node + linkType: hard + "node-stdlib-browser@npm:^1.3.1": version: 1.3.1 resolution: "node-stdlib-browser@npm:1.3.1" @@ -40605,7 +40992,7 @@ __metadata: languageName: node linkType: hard -"obuf@npm:^1.0.0, obuf@npm:^1.1.2, obuf@npm:~1.1.2": +"obuf@npm:^1.0.0, obuf@npm:^1.1.2": version: 1.1.2 resolution: "obuf@npm:1.1.2" checksum: 10/53ff4ab3a13cc33ba6c856cf281f2965c0aec9720967af450e8fd06cfd50aceeefc791986a16bcefa14e7898b3ca9acdfcf15b9d9a1b9c7e1366581a8ad6e65e @@ -41315,6 +41702,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^2.1.0": + version: 2.1.0 + resolution: "parse-ms@npm:2.1.0" + checksum: 10/517eab80cdb9df6ae22a8fad944bfb4289482699bcde5211a1c127091dfea33c3dcb217246b188865fc32e998bcee815bfa4a863f41e3b2d0bcc69f34ef1a543 + languageName: node + linkType: hard + "parse-ms@npm:^4.0.0": version: 4.0.0 resolution: "parse-ms@npm:4.0.0" @@ -41586,7 +41980,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.11.1, path-scurry@npm:^1.6.1": +"path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" dependencies: @@ -41689,13 +42083,6 @@ __metadata: languageName: node linkType: hard -"peek-readable@npm:^7.0.0": - version: 7.0.0 - resolution: "peek-readable@npm:7.0.0" - checksum: 10/e14d533c6a43f3991bb98b644101a55631e307f7fe70e26bd0fd0341bde1e6cdd60e205a66ec17c226b32cb8a4ad5c4e76c1a6173d37201f0bf466cbb617485c - languageName: node - linkType: hard - "pend@npm:~1.2.0": version: 1.2.0 resolution: "pend@npm:1.2.0" @@ -41745,13 +42132,6 @@ __metadata: languageName: node linkType: hard -"pg-numeric@npm:1.0.2": - version: 1.0.2 - resolution: "pg-numeric@npm:1.0.2" - checksum: 10/8899f8200caa1744439a8778a9eb3ceefb599d893e40a09eef84ee0d4c151319fd416634a6c0fc7b7db4ac268710042da5be700b80ef0de716fe089b8652c84f - languageName: node - linkType: hard - "pg-pool@npm:^3.8.0": version: 3.8.0 resolution: "pg-pool@npm:3.8.0" @@ -41781,21 +42161,6 @@ __metadata: languageName: node linkType: hard -"pg-types@npm:^4.0.1": - version: 4.0.1 - resolution: "pg-types@npm:4.0.1" - dependencies: - pg-int8: "npm:1.0.1" - pg-numeric: "npm:1.0.2" - postgres-array: "npm:~3.0.1" - postgres-bytea: "npm:~3.0.0" - postgres-date: "npm:~2.0.1" - postgres-interval: "npm:^3.0.0" - postgres-range: "npm:^1.1.1" - checksum: 10/2c686ef361856ff9695a40cf34d7bb59bcf2218bd1f121d7fc8b77a75cc4106c09519e9520a82aac8fce4540dec81f695458b8e43bfc420ba74eb9b5005b5619 - languageName: node - linkType: hard - "pg@npm:^8.11.3, pg@npm:^8.9.0": version: 8.14.1 resolution: "pg@npm:8.14.1" @@ -42019,27 +42384,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.53.1": - version: 1.53.1 - resolution: "playwright-core@npm:1.53.1" +"playwright-core@npm:1.53.2": + version: 1.53.2 + resolution: "playwright-core@npm:1.53.2" bin: playwright-core: cli.js - checksum: 10/d0ea8674c3abb76069255ca81bc0dfdef3f9548207f1404eec036bb8724135710f25ee791bfd7c043d5b9c2ccfa42288b0308d61dc5efc60a13b18811a15c4cd + checksum: 10/575c37b66aa62e1300d8b42d4b021c9304a35266ea47b6f0c36b429c40674082700b7172ee3641de7451cd2a4c736c42e0e39fd5f6a7ba4c81a6eefd8c104efd languageName: node linkType: hard -"playwright@npm:1.53.1": - version: 1.53.1 - resolution: "playwright@npm:1.53.1" +"playwright@npm:1.53.2": + version: 1.53.2 + resolution: "playwright@npm:1.53.2" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.53.1" + playwright-core: "npm:1.53.2" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/74b3178d5ae3fde8de08fe6c221578530368f1abb8794fce234d06e0043178201eb3b7410354418517f23c105bd54ac1432da5f46c50353a5e6a80198a95f2cf + checksum: 10/1c860c52a77f32793d7b1b5f5b15da9b809b8a09a82e5c89f79442fe9708ff6314b6ee6d13aa0961a6c9fddc9209f0a109ac524bdf586e0df52b641e96fa759d languageName: node linkType: hard @@ -42521,14 +42886,27 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.1.0, postcss@npm:^8.4.33": - version: 8.4.49 - resolution: "postcss@npm:8.4.49" +"postcss-values-parser@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-values-parser@npm:6.0.2" dependencies: - nanoid: "npm:^3.3.7" + color-name: "npm:^1.1.4" + is-url-superb: "npm:^4.0.0" + quote-unquote: "npm:^1.0.0" + peerDependencies: + postcss: ^8.2.9 + checksum: 10/ff2fa096896f1c33f7531e814b8d01e785bd99d672c1597d5c5d8c2409b30b8146be6565f6269c952d1f03d626f00ae3f1afb8308cc772c08b323abee23c9a42 + languageName: node + linkType: hard + +"postcss@npm:^8.1.0, postcss@npm:^8.4.33, postcss@npm:^8.5.1, postcss@npm:^8.5.6": + version: 8.5.6 + resolution: "postcss@npm:8.5.6" + dependencies: + nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/28fe1005b1339870e0a5006375ba5ac1213fd69800f79e7db09c398e074421ba6e162898e94f64942fed554037fd292db3811d87835d25ab5ef7f3c9daacb6ca + checksum: 10/9e4fbe97574091e9736d0e82a591e29aa100a0bf60276a926308f8c57249698935f35c5d2f4e80de778d0cbb8dcffab4f383d85fd50c5649aca421c3df729b86 languageName: node linkType: hard @@ -42539,13 +42917,6 @@ __metadata: languageName: node linkType: hard -"postgres-array@npm:~3.0.1": - version: 3.0.2 - resolution: "postgres-array@npm:3.0.2" - checksum: 10/0159517e4e5f263bf9e324f0c4d3c10244a294021f2b5980abc8c23afdb965370a7fc0c82012fce4d28e83186ad089b6476b05fcef6c88f8e43e37a3a2fa0ad5 - languageName: node - linkType: hard - "postgres-bytea@npm:~1.0.0": version: 1.0.0 resolution: "postgres-bytea@npm:1.0.0" @@ -42553,15 +42924,6 @@ __metadata: languageName: node linkType: hard -"postgres-bytea@npm:~3.0.0": - version: 3.0.0 - resolution: "postgres-bytea@npm:3.0.0" - dependencies: - obuf: "npm:~1.1.2" - checksum: 10/f5c01758fd2fa807afbd34e1ba2146f683818ebc2d23f4a62f0fd627c0b1126fc543cab1b63925f97ce6c7d8f5f316043218619c447445210ea82f10411efb1b - languageName: node - linkType: hard - "postgres-date@npm:~1.0.4": version: 1.0.5 resolution: "postgres-date@npm:1.0.5" @@ -42569,13 +42931,6 @@ __metadata: languageName: node linkType: hard -"postgres-date@npm:~2.0.1": - version: 2.0.1 - resolution: "postgres-date@npm:2.0.1" - checksum: 10/908eacec35faf9b6fa4248074e7c8db0fc4ac6a2e0a00eacef9fb9cf44a25fc6f100af7cda09f5d89d076c87923b59e940a309560d86aded4753985c97255be1 - languageName: node - linkType: hard - "postgres-interval@npm:^1.1.0": version: 1.2.0 resolution: "postgres-interval@npm:1.2.0" @@ -42585,20 +42940,6 @@ __metadata: languageName: node linkType: hard -"postgres-interval@npm:^3.0.0": - version: 3.0.0 - resolution: "postgres-interval@npm:3.0.0" - checksum: 10/c7a1cf006de97de663b6b8c4d2b167aa9909a238c4866a94b15d303762f5ac884ff4796cd6e2111b7f0a91302b83c570453aa8506fd005b5a5d5dfa87441bebc - languageName: node - linkType: hard - -"postgres-range@npm:^1.1.1": - version: 1.1.3 - resolution: "postgres-range@npm:1.1.3" - checksum: 10/356a46d97eab301cca0dbf7a65be6f68c4a7e33d304909e5ca840038b1210390e1d33fcc3b566c42020f7b97e9de189bc5286d1ec8d7ba2445ed3377c576ce9e - languageName: node - linkType: hard - "postman-collection@npm:^4.1.7": version: 4.2.1 resolution: "postman-collection@npm:4.2.1" @@ -42649,6 +42990,31 @@ __metadata: languageName: node linkType: hard +"precinct@npm:^12.2.0": + version: 12.2.0 + resolution: "precinct@npm:12.2.0" + dependencies: + "@dependents/detective-less": "npm:^5.0.1" + commander: "npm:^12.1.0" + detective-amd: "npm:^6.0.1" + detective-cjs: "npm:^6.0.1" + detective-es6: "npm:^5.0.1" + detective-postcss: "npm:^7.0.1" + detective-sass: "npm:^6.0.1" + detective-scss: "npm:^5.0.1" + detective-stylus: "npm:^5.0.1" + detective-typescript: "npm:^14.0.0" + detective-vue2: "npm:^2.2.0" + module-definition: "npm:^6.0.1" + node-source-walk: "npm:^7.0.1" + postcss: "npm:^8.5.1" + typescript: "npm:^5.7.3" + bin: + precinct: bin/cli.js + checksum: 10/fb0cd96b234aa70ede2326971dff039ceee99c4bab68ee8c3f5c3cd09ca67f7a7ae7537121ac49698ef0f9d90f3454e9d3bf2b22bf5ceb745fe4049ec31c9ef0 + languageName: node + linkType: hard + "precond@npm:0.2": version: 0.2.3 resolution: "precond@npm:0.2.3" @@ -42737,6 +43103,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^7.0.1": + version: 7.0.1 + resolution: "pretty-ms@npm:7.0.1" + dependencies: + parse-ms: "npm:^2.1.0" + checksum: 10/a39aac23cc7dae7a94c70518ab8b6c6db0894a7b84c81ee7abc8778c5ec8bae2d1e71ba991ff641732b38433724bfbdbb37bd3a00418637f797c072e06fe8b4c + languageName: node + linkType: hard + "pretty-ms@npm:^9.0.0": version: 9.2.0 resolution: "pretty-ms@npm:9.2.0" @@ -42906,7 +43281,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:15.x, prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": +"prop-types@npm:15.x, prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -43184,6 +43559,13 @@ __metadata: languageName: node linkType: hard +"quote-unquote@npm:^1.0.0": + version: 1.0.0 + resolution: "quote-unquote@npm:1.0.0" + checksum: 10/955a2ead534f5b6a3f8d4dc5a4b95ac6468213d3fb11f8c1592a0a56345c45a3d14d5ca04d3de2bc9891493fcac38c03dfa91c48a6159aef50124e9c5afcea49 + languageName: node + linkType: hard + "raf-schd@npm:^4.0.2": version: 4.0.2 resolution: "raf-schd@npm:4.0.2" @@ -43731,16 +44113,6 @@ __metadata: languageName: node linkType: hard -"react-idle-timer@npm:5.6.2": - version: 5.6.2 - resolution: "react-idle-timer@npm:5.6.2" - peerDependencies: - react: ">=16" - react-dom: ">=16" - checksum: 10/beca4ea53db58a041b562ada6b2eb3de965e9abd1e00f230fbd098114addf668afed907b2e5e31d645be0c02a0648e4837d5bb1644f2cf66428d92f8ef233db4 - languageName: node - linkType: hard - "react-idle-timer@npm:5.7.2": version: 5.7.2 resolution: "react-idle-timer@npm:5.7.2" @@ -44152,18 +44524,6 @@ __metadata: languageName: node linkType: hard -"react-text-truncate@npm:^0.19.0": - version: 0.19.0 - resolution: "react-text-truncate@npm:0.19.0" - dependencies: - prop-types: "npm:^15.5.7" - peerDependencies: - react: ^15.4.1 || ^16.0.0 || ^17.0.0 || || ^18.0.0 - react-dom: ^15.4.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 10/e68e6b924b248b0179e98df5fb654dd6903379df77b9867ee127779b3290c74ead27c75b14b96d759639dc5d07597b4f5f2954bbe543e9cfeff3cff3813e6a72 - languageName: node - linkType: hard - "react-textarea-autosize@npm:^8.3.2": version: 8.4.1 resolution: "react-textarea-autosize@npm:8.4.1" @@ -44791,6 +45151,26 @@ __metadata: languageName: node linkType: hard +"requirejs-config-file@npm:^4.0.0": + version: 4.0.0 + resolution: "requirejs-config-file@npm:4.0.0" + dependencies: + esprima: "npm:^4.0.0" + stringify-object: "npm:^3.2.1" + checksum: 10/9fc55813ca8627cc4d3704622702b6b119a222c97825fc61459727d5f9ef9435e4fd34ee03335dc119c66e834d7963fdfe43d9a4df99448d43219587c624ba4e + languageName: node + linkType: hard + +"requirejs@npm:^2.3.7": + version: 2.3.7 + resolution: "requirejs@npm:2.3.7" + bin: + r.js: bin/r.js + r_js: bin/r.js + checksum: 10/7f42af10d8af210a2769501004b34f9dad4c39716f008f91faeef36c33b60a5f372ca1025c8f40b262f2522fd1ea0f36fd11e9587cba14311fac0df51a8571b0 + languageName: node + linkType: hard + "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -44828,6 +45208,13 @@ __metadata: languageName: node linkType: hard +"resolve-dependency-path@npm:^4.0.1": + version: 4.0.1 + resolution: "resolve-dependency-path@npm:4.0.1" + checksum: 10/db52fc3b970c6784fa5a3695dfeccce0a9dd26d1ea7a4e83a91c30c7be11aed21d27c27c59311c5362fc1c6d2f7f5c40913304a544301c524bc18dbd98837622 + languageName: node + linkType: hard + "resolve-dir@npm:^1.0.0, resolve-dir@npm:^1.0.1": version: 1.0.1 resolution: "resolve-dir@npm:1.0.1" @@ -44879,7 +45266,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": +"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -44918,7 +45305,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin<compat/resolve>": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin<compat/resolve>": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin<compat/resolve>::version=1.22.10&hash=c3c19d" dependencies: @@ -45332,6 +45719,7 @@ __metadata: fs-extra: "npm:^11.2.0" husky: "npm:^9.0.0" lint-staged: "npm:^15.0.0" + madge: "npm:^8.0.0" minimist: "npm:^1.2.5" node-gyp: "npm:^10.0.0" prettier: "npm:^2.2.1" @@ -45517,6 +45905,18 @@ __metadata: languageName: node linkType: hard +"sass-lookup@npm:^6.1.0": + version: 6.1.0 + resolution: "sass-lookup@npm:6.1.0" + dependencies: + commander: "npm:^12.1.0" + enhanced-resolve: "npm:^5.18.0" + bin: + sass-lookup: bin/cli.js + checksum: 10/90a06d5b0545615919f619608019a731eee81939cd0f1f88ed006060222f57de797ad20fc0eb103e13e6a9ff3e620af773e9f3e2ddf69a99fb2ccf4513f47fa4 + languageName: node + linkType: hard + "saxes@npm:^6.0.0": version: 6.0.0 resolution: "saxes@npm:6.0.0" @@ -45856,9 +46256,9 @@ __metadata: linkType: hard "set-cookie-parser@npm:^2.4.6": - version: 2.6.0 - resolution: "set-cookie-parser@npm:2.6.0" - checksum: 10/8d451ebadb760989f93b634942c79de3c925ca7a986d133d08a80c40b5ae713ce12e354f0d5245c49f288c52daa7bd6554d5dc52f8a4eecaaf5e192881cf2b1f + version: 2.7.1 + resolution: "set-cookie-parser@npm:2.7.1" + checksum: 10/c92b1130032693342bca13ea1b1bc93967ab37deec4387fcd8c2a843c0ef2fd9a9f3df25aea5bb3976cd05a91c2cf4632dd6164d6e1814208fb7d7e14edd42b4 languageName: node linkType: hard @@ -46859,7 +47259,7 @@ __metadata: languageName: node linkType: hard -"stream-to-array@npm:~2.3.0": +"stream-to-array@npm:^2.3.0, stream-to-array@npm:~2.3.0": version: 2.3.0 resolution: "stream-to-array@npm:2.3.0" dependencies: @@ -47096,6 +47496,17 @@ __metadata: languageName: node linkType: hard +"stringify-object@npm:^3.2.1": + version: 3.3.0 + resolution: "stringify-object@npm:3.3.0" + dependencies: + get-own-enumerable-property-symbols: "npm:^3.0.0" + is-obj: "npm:^1.0.1" + is-regexp: "npm:^1.0.0" + checksum: 10/973782f09a3df3f39a2cf07dbf43fb9ba6cb32976f3616cd0f6c10e0a5c5415dd72b7b700e72920e8da2bf57c3001b8e37b5af7174bab9a748ce0416989e19b1 + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:6.0, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -47232,13 +47643,12 @@ __metadata: languageName: node linkType: hard -"strtok3@npm:^10.2.0": - version: 10.2.2 - resolution: "strtok3@npm:10.2.2" +"strtok3@npm:^10.2.2": + version: 10.3.1 + resolution: "strtok3@npm:10.3.1" dependencies: "@tokenizer/token": "npm:^0.3.0" - peek-readable: "npm:^7.0.0" - checksum: 10/964e60d76576232803fc75572adfb8778b55a7ef021ecfa3a507dcdb426f1e2c42580e545ab18f882da8f2e9bfca05fb0659f56f71b18723e95c31c0512301fc + checksum: 10/bb7950cc9ce98ec742a5db360630f0b004f16197959ae28d8c8dad4f8f0e405d71cfdc992483038ba29a0b4cbd7227618ad2492005b510d84a3fc5903df0c13f languageName: node linkType: hard @@ -47349,6 +47759,17 @@ __metadata: languageName: node linkType: hard +"stylus-lookup@npm:^6.1.0": + version: 6.1.0 + resolution: "stylus-lookup@npm:6.1.0" + dependencies: + commander: "npm:^12.1.0" + bin: + stylus-lookup: bin/cli.js + checksum: 10/0d998a648025b5e4ad07b65c9f0ee3a0b67cfdbecc352d56e6b2806f9f0ce966ffa287922d3dde7e7e245510a10d6435169dbaa015bdda44cccc60907a2bbce7 + languageName: node + linkType: hard + "sucrase@npm:^3.20.2": version: 3.35.0 resolution: "sucrase@npm:3.35.0" @@ -48289,12 +48710,12 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.0.1": - version: 2.0.1 - resolution: "ts-api-utils@npm:2.0.1" +"ts-api-utils@npm:^2.0.1, ts-api-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "ts-api-utils@npm:2.1.0" peerDependencies: typescript: ">=4.8.4" - checksum: 10/2e68938cd5acad6b5157744215ce10cd097f9f667fd36b5fdd5efdd4b0c51063e855459d835f94f6777bb8a0f334916b6eb5c1eedab8c325feb34baa39238898 + checksum: 10/02e55b49d9617c6eebf8aadfa08d3ca03ca0cd2f0586ad34117fdfc7aa3cd25d95051843fde9df86665ad907f99baed179e7a117b11021417f379e4d2614eacd languageName: node linkType: hard @@ -48312,6 +48733,18 @@ __metadata: languageName: node linkType: hard +"ts-graphviz@npm:^2.1.2": + version: 2.1.6 + resolution: "ts-graphviz@npm:2.1.6" + dependencies: + "@ts-graphviz/adapter": "npm:^2.0.6" + "@ts-graphviz/ast": "npm:^2.0.7" + "@ts-graphviz/common": "npm:^2.1.5" + "@ts-graphviz/core": "npm:^2.0.7" + checksum: 10/7490978263c2365b80b687964c13ad622a05b00e307c1ce448317a551fa1ee7fc03f37cd88d606ba23a030dd3baeb5b147d06d5af087b73133ac9276a7d65449 + languageName: node + linkType: hard + "ts-interface-checker@npm:^0.1.9": version: 0.1.13 resolution: "ts-interface-checker@npm:0.1.13" @@ -48706,19 +49139,19 @@ __metadata: linkType: hard "typedoc@npm:^0.28.0": - version: 0.28.4 - resolution: "typedoc@npm:0.28.4" + version: 0.28.7 + resolution: "typedoc@npm:0.28.7" dependencies: - "@gerrit0/mini-shiki": "npm:^3.2.2" + "@gerrit0/mini-shiki": "npm:^3.7.0" lunr: "npm:^2.3.9" markdown-it: "npm:^14.1.0" minimatch: "npm:^9.0.5" - yaml: "npm:^2.7.1" + yaml: "npm:^2.8.0" peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x bin: typedoc: bin/typedoc - checksum: 10/0ccab46519e4be1aa9bd4defd55e920cbefe8825e0ba7ca93b8d6fd3867300e8b60260d2182033b46121f9040251366f6a496a3500da458c3031b224d7bdadd7 + checksum: 10/afe4868d9288c8456227d745955eeb37a0485b56657d4b690d32e2c99580983cf27109e197b5c652c747cfcdab81588c9ff3d1572e9d7d87fd068e8630715b18 languageName: node linkType: hard @@ -48759,6 +49192,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.7.3, typescript@npm:^5.8.3": + version: 5.8.3 + resolution: "typescript@npm:5.8.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/65c40944c51b513b0172c6710ee62e951b70af6f75d5a5da745cb7fab132c09ae27ffdf7838996e3ed603bb015dadd099006658046941bd0ba30340cc563ae92 + languageName: node + linkType: hard + "typescript@npm:~5.5.0": version: 5.5.4 resolution: "typescript@npm:5.5.4" @@ -48789,6 +49232,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.7.3#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin<compat/typescript>": + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>::version=5.8.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/b9b1e73dabac5dc730c041325dbd9c99467c1b0d239f1b74ec3b90d831384af3e2ba973946232df670519147eb51a2c20f6f96163cea2b359f03de1e2091cc4f + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A~5.5.0#optional!builtin<compat/typescript>": version: 5.5.4 resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin<compat/typescript>::version=5.5.4&hash=379a07" @@ -49789,6 +50242,13 @@ __metadata: languageName: node linkType: hard +"walkdir@npm:^0.4.1": + version: 0.4.1 + resolution: "walkdir@npm:0.4.1" + checksum: 10/54cbe7afc5fb811a55748b0bfa077a9a4aa43f568eb5857db9785af9728e1ad8b1ecf6b9ce6f14b405c6124939a92522e36aaa0397f3f52a9a7a08496f2eebe1 + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -50526,12 +50986,12 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4, yaml@npm:^2.7.0, yaml@npm:^2.7.1": - version: 2.7.1 - resolution: "yaml@npm:2.7.1" +"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4, yaml@npm:^2.7.0, yaml@npm:^2.8.0": + version: 2.8.0 + resolution: "yaml@npm:2.8.0" bin: yaml: bin.mjs - checksum: 10/af57658d37c5efae4bac7204589b742ae01878a278554d632f01012868cf7fa66cba09b39140f12e7f6ceecc693ae52bcfb737596c4827e6e233338cb3a9528e + checksum: 10/7d4bd9c10d0e467601f496193f2ac254140f8e36f96f5ff7f852b9ce37974168eb7354f4c36dc8837dde527a2043d004b6aff48818ec24a69ab2dd3c6b6c381c languageName: node linkType: hard