diff --git a/.changeset/afraid-poets-thank.md b/.changeset/afraid-poets-thank.md new file mode 100644 index 0000000000..b234e2e2c1 --- /dev/null +++ b/.changeset/afraid-poets-thank.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Fix card scrolling behaviour 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/bright-elephants-sparkle.md b/.changeset/bright-elephants-sparkle.md new file mode 100644 index 0000000000..05dc6150c6 --- /dev/null +++ b/.changeset/bright-elephants-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Created a flag for scaffolding apps using the new frontend system. diff --git a/.changeset/calm-geese-serve.md b/.changeset/calm-geese-serve.md new file mode 100644 index 0000000000..ff52f59b56 --- /dev/null +++ b/.changeset/calm-geese-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Remove usage of the deprecated `loggerToWinstonLogger` from `@backstage/backend-common`. diff --git a/.changeset/chatty-dodos-design.md b/.changeset/chatty-dodos-design.md new file mode 100644 index 0000000000..d998f09250 --- /dev/null +++ b/.changeset/chatty-dodos-design.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +'@backstage/backend-defaults': patch +--- + +Fixed WinstonLogger throwing when redactions were null or undefined 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/clean-chairs-sit-2.md b/.changeset/clean-chairs-sit-2.md new file mode 100644 index 0000000000..6fb7d6c844 --- /dev/null +++ b/.changeset/clean-chairs-sit-2.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +**DEPRECATION**: The following types have been deprecated from this package and moved into `@backstage/plugin-scaffolder-common` and should be imported from there instead. + +`Action`, `ListActionsResponse`, `LogEvent`, `ScaffolderApi`, `ScaffolderDryRunOptions`, `ScaffolderDryRunResponse`, `ScaffolderGetIntegrationsListOptions`, `ScaffolderGetIntegrationsListResponse`, +`ScaffolderOutputLink`, `ScaffolderOutputText`, `ScaffolderScaffoldOptions`, `ScaffolderScaffoldResponse`, `ScaffolderStreamLogsOptions`, `ScaffolderTask`, `ScaffolderTaskOutput`, `ScaffolderTaskStatus`, +`ScaffolderUsageExample`, `TemplateFilter`, `TemplateGlobalFunction`, `TemplateGlobalValue`, `TemplateParameterSchema`. diff --git a/.changeset/clean-chairs-sit.md b/.changeset/clean-chairs-sit.md new file mode 100644 index 0000000000..9e76e56887 --- /dev/null +++ b/.changeset/clean-chairs-sit.md @@ -0,0 +1,10 @@ +--- +'@backstage/backend-openapi-utils': minor +'@backstage/plugin-scaffolder-backend': minor +'@backstage/plugin-scaffolder-common': minor +'@backstage/plugin-scaffolder-react': minor +'@backstage/plugin-scaffolder-node': minor +'@backstage/plugin-scaffolder': minor +--- + +Move Scaffolder API to OpenAPI diff --git a/.changeset/common-heads-build.md b/.changeset/common-heads-build.md new file mode 100644 index 0000000000..2874ea7594 --- /dev/null +++ b/.changeset/common-heads-build.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Fixes some styles on the Select component in BUI. 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/eleven-tigers-drop.md b/.changeset/eleven-tigers-drop.md new file mode 100644 index 0000000000..ea2702cfb5 --- /dev/null +++ b/.changeset/eleven-tigers-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': patch +--- + +Add the missing Visits API to the alpha plugin, fixing a crash due to the API not being installed. diff --git a/.changeset/every-schools-find.md b/.changeset/every-schools-find.md new file mode 100644 index 0000000000..b4cb15bf52 --- /dev/null +++ b/.changeset/every-schools-find.md @@ -0,0 +1,20 @@ +--- +'@backstage/plugin-catalog-unprocessed-entities': patch +'@backstage/frontend-app-api': patch +'@backstage/core-compat-api': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-notifications': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-signals': patch +'@backstage/plugin-search': patch +'@backstage/plugin-home': patch +'@backstage/plugin-app': patch +--- + +Internal update to use the new variant of `ApiBlueprint`. diff --git a/.changeset/evil-forks-hang.md b/.changeset/evil-forks-hang.md new file mode 100644 index 0000000000..f261c48c2b --- /dev/null +++ b/.changeset/evil-forks-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': minor +--- + +Added the `analyzeLocation` method to `catalogApiMock` 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/fifty-ads-dance.md b/.changeset/fifty-ads-dance.md new file mode 100644 index 0000000000..79801caafd --- /dev/null +++ b/.changeset/fifty-ads-dance.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Fixes a couple of small bugs in BUI including setting H1 and H2 correctly on the Header and HeaderPage. diff --git a/.changeset/five-ducks-hide.md b/.changeset/five-ducks-hide.md new file mode 100644 index 0000000000..6ce1fec8f7 --- /dev/null +++ b/.changeset/five-ducks-hide.md @@ -0,0 +1,31 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +**BREAKING**: The `NavLogoBlueprint` has been removed and replaced by `NavContentBlueprint`, which instead replaces the entire navbar. The default navbar has also been switched to a more minimal implementation. + +To use `NavContentBlueprint` to install new logos, you can use it as follows: + +```tsx +NavContentBlueprint.make({ + params: { + component: ({ items }) => { + return compatWrapper( + + + + {/* Other sidebar content */} + + + {items.map((item, index) => ( + + ))} + + + {/* Other sidebar content */} + , + ); + }, + }, +}); +``` diff --git a/.changeset/full-streets-take.md b/.changeset/full-streets-take.md new file mode 100644 index 0000000000..f04cd92c57 --- /dev/null +++ b/.changeset/full-streets-take.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app': minor +--- + +Updated the `app/nav` extension to use the new `NavContentBlueprint`, and removed support for extensions created with the now removed `NavLogoBlueprint`. 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/fuzzy-ducks-speak.md b/.changeset/fuzzy-ducks-speak.md new file mode 100644 index 0000000000..30e23c7ca5 --- /dev/null +++ b/.changeset/fuzzy-ducks-speak.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +The `description` property in `publish:gitlab:merge-request` has been made optional again to comply with the GitLab API. diff --git a/.changeset/great-snakes-dress.md b/.changeset/great-snakes-dress.md new file mode 100644 index 0000000000..404bdab03c --- /dev/null +++ b/.changeset/great-snakes-dress.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +We are introducing two new data attributes on the `body` to support Backstage UI (BUI) new theming system. 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/huge-paws-design.md b/.changeset/huge-paws-design.md new file mode 100644 index 0000000000..8d90435480 --- /dev/null +++ b/.changeset/huge-paws-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +We are motion away from `motion` to use `gsap` instead to make Backstage UI backward compatible with React 17. diff --git a/.changeset/little-bugs-care.md b/.changeset/little-bugs-care.md new file mode 100644 index 0000000000..930cbd0e21 --- /dev/null +++ b/.changeset/little-bugs-care.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': minor +--- + +Added the analyze-location endpoint to the CatalogClient diff --git a/.changeset/long-grapes-glow.md b/.changeset/long-grapes-glow.md new file mode 100644 index 0000000000..e0e805ed87 --- /dev/null +++ b/.changeset/long-grapes-glow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-node': minor +--- + +Added the analyze-location endpoint to the CatalogService diff --git a/.changeset/lovely-fans-write.md b/.changeset/lovely-fans-write.md new file mode 100644 index 0000000000..71b02f2bde --- /dev/null +++ b/.changeset/lovely-fans-write.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +differentiate between entirely and partially composite schemas in schema rendering diff --git a/.changeset/mighty-cycles-stay.md b/.changeset/mighty-cycles-stay.md new file mode 100644 index 0000000000..cb1bb3646e --- /dev/null +++ b/.changeset/mighty-cycles-stay.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-react': patch +--- + +Export `FormField` type from `/alpha` in `-react` package, and internal refactor. 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-buttons-return.md b/.changeset/nice-buttons-return.md new file mode 100644 index 0000000000..a47a3aa1a7 --- /dev/null +++ b/.changeset/nice-buttons-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': minor +--- + +Adds `additionalAllowedURIProtocols` to sanitizer config 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/odd-beans-sell.md b/.changeset/odd-beans-sell.md new file mode 100644 index 0000000000..50b8ec0f89 --- /dev/null +++ b/.changeset/odd-beans-sell.md @@ -0,0 +1,40 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +**BREAKING**: The `ApiBlueprint` has been updated to use the new advanced type parameters through the new `defineParams` blueprint option. This is an immediate breaking change that requires all existing usages of `ApiBlueprint` to switch to the new callback format. Existing extensions created with the old format are still compatible with the latest version of the plugin API however, meaning that this does not break existing plugins. + +To update existing usages of `ApiBlueprint`, you remove the outer level of the `params` object and replace `createApiFactory(...)` with `define => define(...)`. + +For example, the following old usage: + +```ts +ApiBlueprint.make({ + name: 'error', + params: { + factory: createApiFactory({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => { + return ...; + }, + }) + }, +}) +``` + +is migrated to the following: + +```ts +ApiBlueprint.make({ + name: 'error', + params: define => + define({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => { + return ...; + }, + }), +}) +``` diff --git a/.changeset/open-seas-ring.md b/.changeset/open-seas-ring.md new file mode 100644 index 0000000000..d8249f940c --- /dev/null +++ b/.changeset/open-seas-ring.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +hide pagination `queryparams` if pagination mode is set to none diff --git a/.changeset/polite-trains-notice.md b/.changeset/polite-trains-notice.md new file mode 100644 index 0000000000..6b204b2b10 --- /dev/null +++ b/.changeset/polite-trains-notice.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Updated Menu component in Backstage UI to use useId() from React Aria instead of React to support React 17. diff --git a/.changeset/pre.json b/.changeset/pre.json index 60eb6ca6ce..fff8034b0a 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,206 +2,249 @@ "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": [ + "afraid-poets-thank", + "blue-apples-pump", + "bright-elephants-sparkle", + "calm-geese-serve", + "chatty-dodos-design", + "clean-chairs-sit-2", + "clean-chairs-sit", + "common-heads-build", + "create-app-1753196727", + "eleven-tigers-drop", + "every-schools-find", + "evil-forks-hang", + "evil-phones-unite", + "fifty-ads-dance", + "five-ducks-hide", + "full-streets-take", + "funny-dancers-start", + "fuzzy-ducks-speak", + "great-snakes-dress", + "hot-clowns-behave", + "huge-heads-occur", + "huge-paws-design", + "little-bugs-care", + "long-grapes-glow", + "lovely-fans-write", + "mighty-cycles-stay", + "nice-actors-cheer", + "nice-buttons-return", + "nice-crabs-clean", + "odd-beans-sell", + "open-seas-ring", + "quiet-parks-cheer", + "ripe-comics-sip", + "spotty-clowns-lose", + "spotty-icons-shake", + "tender-crabs-stay", + "thirty-jobs-cut", + "tired-lamps-start", + "twenty-pumas-brush", + "wild-apes-care", + "yellow-ducks-burn" + ] } diff --git a/.changeset/quiet-parks-cheer.md b/.changeset/quiet-parks-cheer.md new file mode 100644 index 0000000000..31e1ff8435 --- /dev/null +++ b/.changeset/quiet-parks-cheer.md @@ -0,0 +1,42 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +Added support for advanced parameter types in extension blueprints. The primary purpose of this is to allow extension authors to use type inference in the definition of the blueprint parameters. This often removes the need for extra imports and improves discoverability of blueprint parameters. + +This feature is introduced through the new `defineParams` option of `createExtensionBlueprint`, along with accompanying `createExtensionBlueprintParams` function to help implement the new format. + +The following is an example of how to create an extension blueprint that uses the new option: + +```ts +const ExampleBlueprint = createExtensionBlueprint({ + kind: 'example', + attachTo: { id: 'example', input: 'example' }, + output: [exampleComponentDataRef, exampleFetcherDataRef], + defineParams(params: { + component(props: ExampleProps): JSX.Element | null; + fetcher(options: FetchOptions): Promise>; + }) { + // The returned params must be wrapped with `createExtensionBlueprintParams` + return createExtensionBlueprintParams(params); + }, + *factory(params) { + // These params are now inferred + yield exampleComponentDataRef(params.component); + yield exampleFetcherDataRef(params.fetcher); + }, +}); +``` + +Usage of the above example looks as follows: + +```ts +const example = ExampleBlueprint.make({ + params: define => define({ + component: ..., + fetcher: ..., + }), +}); +``` + +This `define => define()` is also known as the "callback syntax" and is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible. 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/ripe-comics-sip.md b/.changeset/ripe-comics-sip.md new file mode 100644 index 0000000000..b5fb1e7f2b --- /dev/null +++ b/.changeset/ripe-comics-sip.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +This change introduces single user versions of the user group resolution code in the multi org provider that will not page through all membership when updating a single user. diff --git a/.changeset/sad-cities-lay.md b/.changeset/sad-cities-lay.md new file mode 100644 index 0000000000..141c093b46 --- /dev/null +++ b/.changeset/sad-cities-lay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Updated CachedEntityLoader to use BackstageCredentials instead of raw tokens for cache key generation. It now uses principal-based identification (user entity ref for users, subject for services) instead of token-based keys, providing more consistent caching behavior. 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-clowns-lose.md b/.changeset/spotty-clowns-lose.md new file mode 100644 index 0000000000..e550fe48de --- /dev/null +++ b/.changeset/spotty-clowns-lose.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Added `stringEnums` to `mustache` templates 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/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/thirty-jobs-cut.md b/.changeset/thirty-jobs-cut.md new file mode 100644 index 0000000000..6875a92271 --- /dev/null +++ b/.changeset/thirty-jobs-cut.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch +'@backstage/plugin-catalog-backend': patch +--- + +Updated `better-sqlite3` to v12 diff --git a/.changeset/tired-lamps-start.md b/.changeset/tired-lamps-start.md new file mode 100644 index 0000000000..97b4e61ca3 --- /dev/null +++ b/.changeset/tired-lamps-start.md @@ -0,0 +1,15 @@ +--- +'@backstage/create-app': patch +--- + +Updated the `better-sqlite` dependency from `v9.0.0` to `v13.0.0`. You can apply this change to your instance by applying the following change to your `packages/backend/package.json` and running `yarn install`. + +```diff + "dependencies": { + "app": "link:../app", +- "better-sqlite3": "^9.0.0", ++ "better-sqlite3": "^12.0.0", + "node-gyp": "^10.0.0", + "pg": "^8.11.3" + } +``` 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/wild-apes-care.md b/.changeset/wild-apes-care.md new file mode 100644 index 0000000000..36bc822ec8 --- /dev/null +++ b/.changeset/wild-apes-care.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-node-test-utils': patch +'@backstage/plugin-scaffolder-backend': minor +'@backstage/plugin-scaffolder-node': patch +--- + +Add step info to scaffolder action context to access the step id and name. diff --git a/.changeset/yellow-ducks-burn.md b/.changeset/yellow-ducks-burn.md new file mode 100644 index 0000000000..c76a548d54 --- /dev/null +++ b/.changeset/yellow-ducks-burn.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Allow js files to be processed by the nodeTransform loader 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..c4cfa40a3c 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 @@ -285,6 +288,7 @@ namespaced namespaces Namespaces namespacing +navbar neuro newrelic nginx @@ -312,8 +316,8 @@ OpenSearch OpenShift openssl orgs -Overridable overridable +Overridable padding paddings pagerduty @@ -364,6 +368,7 @@ readonly rebase rebasing Recharts +redactions Redash redis reimplement @@ -380,10 +385,10 @@ retryable reusability Reusability roadmaps -rollbar -rollout Roboto +rollbar Rollbar +rollout Rollup routable Routable @@ -399,9 +404,10 @@ sanitization scaffolded scaffolder Scaffolder -scrollbar SCM SCMs +scrollable +scrollbar sdks seb semlas @@ -409,14 +415,15 @@ semver sendmail serializable Serverless +severities shoutout SIG signoff SIGs siloed Sinon -snackbars snackbar +snackbars Snyk Sonarqube sourcemaps @@ -487,6 +494,7 @@ transpiled transpiler transpilers truthy +tsconfig TSDoc typeahead ui @@ -537,7 +545,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 21913eb428..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 @@ -52,14 +52,14 @@ jobs: working-directory: ./example-app - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Build and push uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 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/app-config.yaml b/app-config.yaml index 89926357c2..910a3e4f99 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -138,7 +138,6 @@ integrations: secretAccessKey: ${AWS_SECRET_ACCESS_KEY} catalog: - useUrlReadersSearch: true import: entityFilename: catalog-info.yaml pullRequestBranchName: backstage-integration 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/css-classname-structure.png b/canon-docs/public/css-classname-structure.png deleted file mode 100644 index df9894ff2b..0000000000 Binary files a/canon-docs/public/css-classname-structure.png and /dev/null differ 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/scripts/build-css.js b/canon-docs/scripts/build-css.js deleted file mode 100644 index dd9775150f..0000000000 --- a/canon-docs/scripts/build-css.js +++ /dev/null @@ -1,39 +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}/core.css`); -const destination1 = path.join(__dirname, `${destination}/core.css`); -const source2 = path.join(__dirname, `${source}/components.css`); -const destination2 = path.join(__dirname, `${destination}/components.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), - bundleAndCopyFile(source2, destination2), -]) - .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/(docs)/page.mdx b/canon-docs/src/app/(docs)/page.mdx deleted file mode 100644 index 862127ec7b..0000000000 --- a/canon-docs/src/app/(docs)/page.mdx +++ /dev/null @@ -1,51 +0,0 @@ -import { CodeBlock } from '@/components/CodeBlock'; - - - -Welcome to the Canon, 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 -building it incrementally with not conflict with the existing theming system. - -## Installation - -### 1. Install canon - -Install Canon 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'; -``` - -### 3. Start building ✨ - -Now you can start building your plugin using the new design system. - -```tsx -import { Flex, Button, Text } from '@backstage/canon'; - - - Hello World - -; -``` - -## 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. -Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system. -If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2). diff --git a/canon-docs/src/app/(docs)/theme/typography/page.mdx b/canon-docs/src/app/(docs)/theme/typography/page.mdx deleted file mode 100644 index 98a342bc91..0000000000 --- a/canon-docs/src/app/(docs)/theme/typography/page.mdx +++ /dev/null @@ -1,65 +0,0 @@ -import { HeadingSnippet, TextSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; - -# Typography - -Canon 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 -define different typography values for various breakpoints. - -## Headings - -Headings are used to structure the content of your page. They are used to -create a hierarchy of information and to make the content more readable. The -best way to use add these headings to your page is to import the [Heading -component](?path=/docs/components-heading--docs). - -} - code={` - Display - Title 1 - Title 2 - Title 3 - Title 4 -`} -/> - -## Text - -Canon 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 -page. - -} - code={` - - 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? - - `} -/> 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/icon.svg b/canon-docs/src/app/icon.svg deleted file mode 100644 index 12cad81e95..0000000000 --- a/canon-docs/src/app/icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - 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/app/opengraph-image.jpg b/canon-docs/src/app/opengraph-image.jpg deleted file mode 100644 index 4dc9025ec5..0000000000 Binary files a/canon-docs/src/app/opengraph-image.jpg and /dev/null differ 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 eb1c3213cc..0000000000 --- a/canon-docs/src/components/Sidebar/playground.tsx +++ /dev/null @@ -1,78 +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/components/Toolbar/theme-name.module.css b/canon-docs/src/components/Toolbar/theme-name.module.css deleted file mode 100644 index 87d6538e81..0000000000 --- a/canon-docs/src/components/Toolbar/theme-name.module.css +++ /dev/null @@ -1,138 +0,0 @@ -.Select { - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem; - height: 2rem; - padding-left: 0.875rem; - padding-right: 0.75rem; - margin: 0; - outline: 0; - border: 1px solid var(--color-gray-200); - border-radius: 0.375rem; - 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; - - &:focus-visible { - outline: 2px solid var(--color-blue); - outline-offset: -1px; - } -} - -.SelectIcon { - display: flex; -} - -.SelectValue { - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-regular); -} - -.Positioner { - z-index: 20; -} - -.Popup { - box-sizing: border-box; - padding-block: 0.25rem; - border-radius: 0.375rem; - background-color: var(--panel); - color: var(--color-gray-900); - border: 1px solid var(--border); - padding-inline: 0.25rem; - transform-origin: var(--transform-origin); - transition: transform 150ms, opacity 150ms; - - &[data-starting-style], - &[data-ending-style] { - opacity: 0; - transform: scale(0.9); - } - - &[data-side='none'] { - transition: none; - transform: none; - opacity: 1; - } - - @media (prefers-color-scheme: light) { - outline: 1px solid var(--color-gray-200); - box-shadow: 0px 10px 15px -3px var(--color-gray-200), - 0px 4px 6px -4px var(--color-gray-200); - } - - @media (prefers-color-scheme: dark) { - outline: 1px solid var(--color-gray-300); - outline-offset: -1px; - } -} - -.Item { - box-sizing: border-box; - outline: 0; - font-size: 0.875rem; - line-height: 1rem; - 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); - display: grid; - gap: 0.5rem; - align-items: center; - grid-template-columns: 0.75rem 1fr; - cursor: default; - user-select: none; - border-radius: 0.25rem; - cursor: pointer; - transition: background-color 0.2s ease-in-out; - - [data-side='none'] & { - font-size: 1rem; - padding-right: 3rem; - min-width: calc(var(--anchor-width) + 1rem); - } - - &[data-highlighted] { - z-index: 0; - position: relative; - color: var(--color-gray-50); - background-color: var(--bg); - } - - &[data-highlighted]::before { - content: ''; - z-index: -1; - position: absolute; - inset-block: 0; - inset-inline: 0.25rem; - border-radius: 0.25rem; - background-color: var(--color-gray-900); - } -} - -.ItemIndicator { - grid-column-start: 1; - width: 1rem; - height: 1rem; - display: flex; - align-items: center; -} - -.ItemIndicatorIcon { - display: block; - width: 0.75rem; - height: 0.75rem; -} - -.ItemText { - grid-column-start: 2; - font-size: 14px; -} diff --git a/canon-docs/src/components/Toolbar/theme-name.tsx b/canon-docs/src/components/Toolbar/theme-name.tsx deleted file mode 100644 index 277ecad9df..0000000000 --- a/canon-docs/src/components/Toolbar/theme-name.tsx +++ /dev/null @@ -1,48 +0,0 @@ -'use client'; - -import { Select } from '@base-ui-components/react/select'; -import styles from './theme-name.module.css'; -import { Icon } from '@backstage/canon'; -import { usePlayground } from '@/utils/playground-context'; - -const themes = [ - { name: 'Backstage', value: 'default' }, - { name: 'Custom theme', value: 'custom' }, -]; - -export const ThemeNameSelector = () => { - const { selectedThemeName, setSelectedThemeName } = usePlayground(); - - return ( - - - - - - - - - - - {themes.map(({ name, value }) => ( - - - - - - {name} - - - ))} - - - - - ); -}; 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/icon-button.mdx b/canon-docs/src/content/components/icon-button.mdx deleted file mode 100644 index 80e7e5a46d..0000000000 --- a/canon-docs/src/content/components/icon-button.mdx +++ /dev/null @@ -1,79 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { CodeBlock } from '@/components/CodeBlock'; -import { IconButtonSnippet } from '@/snippets/stories-snippets'; -import { - iconButtonPropDefs, - iconButtonUsageSnippet, - iconButtonDefaultSnippet, - iconButtonVariantsSnippet, - iconButtonSizesSnippet, - iconButtonDisabledSnippet, - iconButtonResponsiveSnippet, -} from './icon-button.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; - -# Icon Button - -A button component with a single icon that can be used to trigger actions. - -} - code={iconButtonDefaultSnippet} -/> - - - -## API reference - - - -## Examples - -### Variants - -Here's a view when buttons have different variants. - -} - code={iconButtonVariantsSnippet} -/> - -### Sizes - -Here's a view when buttons have different sizes. - -} - code={iconButtonSizesSnippet} -/> - -### Disabled - -Here's a view when buttons are disabled. - -} - code={iconButtonDisabledSnippet} -/> - -### Responsive - -Here's a view when buttons are responsive. - - diff --git a/canon-docs/src/content/components/icon-button.props.ts b/canon-docs/src/content/components/icon-button.props.ts deleted file mode 100644 index 8fdfaba6b9..0000000000 --- a/canon-docs/src/content/components/icon-button.props.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - classNamePropDefs, - stylePropDefs, - type PropDef, -} from '@/utils/propDefs'; - -export const iconButtonPropDefs: Record = { - variant: { - type: 'enum', - values: ['primary', 'secondary'], - default: 'primary', - responsive: true, - }, - size: { - type: 'enum', - values: ['small', 'medium'], - default: 'medium', - responsive: true, - }, - icon: { type: 'enum', values: 'icon', responsive: false }, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const iconButtonUsageSnippet = `import { IconButton } from '@backstage/canon'; - -`; - -export const iconButtonDefaultSnippet = ` - - -`; - -export const iconButtonVariantsSnippet = ` - - -`; - -export const iconButtonSizesSnippet = ` - - -`; - -export const iconButtonDisabledSnippet = ``; - -export const iconButtonResponsiveSnippet = ``; 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/tabs.mdx b/canon-docs/src/content/components/tabs.mdx deleted file mode 100644 index 85cfa34af2..0000000000 --- a/canon-docs/src/content/components/tabs.mdx +++ /dev/null @@ -1,61 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { TabsSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; -import { CodeBlock } from '@/components/CodeBlock'; -import { - tabsRootPropDefs, - tabsListPropDefs, - tabsTabPropDefs, - tabsPanelPropDefs, - tabsUsageSnippet, - tabsDefaultSnippet, -} from './tabs.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; - -# Tabs - -A component for toggling between related panels on the same page. - -} - code={tabsDefaultSnippet} -/> - - - -## API reference - -### Tabs.Root - -Groups the tabs and the corresponding panels. Renders a `
` element. - - - -### Tabs.List - -Groups the individual tab buttons. Renders a `
` element. - - - -### Tabs.Tab - -An individual interactive tab button that toggles the corresponding panel. Renders a ` +; +``` + +## Next steps + +Now that you have the basics down, you can start building your plugin using the new design system. +Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system. +If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2). 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..d90f1c06a4 --- /dev/null +++ b/docs-ui/src/app/layout.tsx @@ -0,0 +1,64 @@ +import type { Metadata } from 'next'; +import { Sidebar } from '../components/Sidebar'; +import { Toolbar } from '@/components/Toolbar'; +import { StickyHeader } from '../components/StickyHeader/StickyHeader'; +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/(docs)/theme/layout/page.mdx b/docs-ui/src/app/layout/page.mdx similarity index 94% rename from canon-docs/src/app/(docs)/theme/layout/page.mdx rename to docs-ui/src/app/layout/page.mdx index b069082b04..3c3b998490 100644 --- a/canon-docs/src/app/(docs)/theme/layout/page.mdx +++ b/docs-ui/src/app/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/docs-ui/src/app/opengraph-image.jpg b/docs-ui/src/app/opengraph-image.jpg new file mode 100644 index 0000000000..86546a32ee Binary files /dev/null and b/docs-ui/src/app/opengraph-image.jpg differ diff --git a/docs-ui/src/app/page.mdx b/docs-ui/src/app/page.mdx new file mode 100644 index 0000000000..f31cf4524e --- /dev/null +++ b/docs-ui/src/app/page.mdx @@ -0,0 +1,174 @@ +import { ComponentCards, ComponentCard } from '@/components/ComponentCards'; + +## Welcome to 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 +building it incrementally with not conflict with the existing theming system. + +### Actions + + + + + + + + +### Layout + + + + + + + + + + +### Selection and inputs + + + + + + + + + + +### Navigation + + + + + + + + +### Images and icons + + + + + + +### Feedback indicators + + + + + + +### Typography + + + + + +## Support + +Now that you have the basics down, you can start building your plugin using the new design system. +Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system. +If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2). 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/responsive/page.mdx b/docs-ui/src/app/responsive/page.mdx similarity index 94% rename from canon-docs/src/app/(docs)/theme/responsive/page.mdx rename to docs-ui/src/app/responsive/page.mdx index 7eb4411333..9d37b1329f 100644 --- a/canon-docs/src/app/(docs)/theme/responsive/page.mdx +++ b/docs-ui/src/app/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/theming/page.mdx similarity index 73% rename from canon-docs/src/app/(docs)/theme/theming/page.mdx rename to docs-ui/src/app/theming/page.mdx index ed7f801db0..5205690d0b 100644 --- a/canon-docs/src/app/(docs)/theme/theming/page.mdx +++ b/docs-ui/src/app/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/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/docs-ui/src/components/ComponentCards/ComponentCards.module.css b/docs-ui/src/components/ComponentCards/ComponentCards.module.css new file mode 100644 index 0000000000..688010110c --- /dev/null +++ b/docs-ui/src/components/ComponentCards/ComponentCards.module.css @@ -0,0 +1,54 @@ +.grid { + display: grid; + grid-template-columns: repeat(1, 1fr); + gap: 1rem; + margin-top: 1rem; + margin-bottom: 3rem; +} + +@media (min-width: 768px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .grid { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (min-width: 1280px) { + .grid { + grid-template-columns: repeat(4, 1fr); + } +} + +.card { + display: flex; + flex-direction: column; + justify-content: flex-end; + background-color: var(--panel); + border-radius: 8px; + border: 1px solid var(--border); + padding: 16px; + gap: 4px; + min-height: 120px; + + &:hover { + background-color: var(--panel-hover); + } +} + +.title { + margin: 0; + font-size: 16px; + font-weight: 600; + color: var(--primary); +} + +.description { + margin: 0; + font-size: 14px; + color: var(--secondary); +} diff --git a/docs-ui/src/components/ComponentCards/ComponentCards.tsx b/docs-ui/src/components/ComponentCards/ComponentCards.tsx new file mode 100644 index 0000000000..0e4d22c02a --- /dev/null +++ b/docs-ui/src/components/ComponentCards/ComponentCards.tsx @@ -0,0 +1,23 @@ +import Link from 'next/link'; +import styles from './ComponentCards.module.css'; + +export const ComponentCards = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +export const ComponentCard = ({ + title, + description, + href, +}: { + title: string; + description: string; + href: string; +}) => { + return ( + +

{title}

+

{description}

+ + ); +}; diff --git a/docs-ui/src/components/ComponentCards/index.ts b/docs-ui/src/components/ComponentCards/index.ts new file mode 100644 index 0000000000..4bc4beaae3 --- /dev/null +++ b/docs-ui/src/components/ComponentCards/index.ts @@ -0,0 +1 @@ +export * from './ComponentCards'; 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 84% rename from canon-docs/src/components/PropsTable/PropsTable.tsx rename to docs-ui/src/components/PropsTable/PropsTable.tsx index a017dc557c..bd54b1e245 100644 --- a/canon-docs/src/components/PropsTable/PropsTable.tsx +++ b/docs-ui/src/components/PropsTable/PropsTable.tsx @@ -2,15 +2,13 @@ import * as Table from '../Table'; import { Chip } from '../Chip'; -import { icons } from '../../../../packages/canon'; +import { TypePopup } from './TypePopup'; +import { icons } from '../../../../packages/ui'; -// Define a more specific type for the data object -type PropData = { - values?: string | string[]; - responsive?: boolean; - default?: string; - type?: string; -}; +import { PropDef } from '@/utils/propDefs'; + +// Use the proper PropDef type +type PropData = PropDef; // Modify the PropsTable component to use the new type export const PropsTable = >({ @@ -59,6 +57,12 @@ export const PropsTable = >({ string )} + {data[n].type === 'complex' && data[n].complexType && ( + + )} {data[n].type === 'enum | string' && ( <> {enumValues} diff --git a/docs-ui/src/components/PropsTable/TypePopup.module.css b/docs-ui/src/components/PropsTable/TypePopup.module.css new file mode 100644 index 0000000000..294df0b645 --- /dev/null +++ b/docs-ui/src/components/PropsTable/TypePopup.module.css @@ -0,0 +1,79 @@ +.button { + display: inline-flex; + align-items: center; + font-family: monospace; + font-size: 13px; + border-radius: 6px; + padding: 0px 8px; + height: 24px; + margin-right: 4px; + background-color: #f0f0f0; + color: #5d5d5d; + cursor: pointer; + border: none; + outline: none; + box-shadow: none; + text-decoration: underline; +} + +[data-theme='dark'] .button { + background-color: #2c2c2c; + color: #fff; +} + +.popover { + border: 1px solid var(--border); + box-shadow: 0 8px 20px rgba(0 0 0 / 0.1); + border-radius: 6px; + background: var(--panel); + color: var(--primary); + outline: none; + /* max-width: 400px; */ + transition: transform 200ms, opacity 200ms; + padding: 1rem; + margin-top: 6px; + --origin: translateY(-8px); + + &[data-entering], + &[data-exiting] { + transform: var(--origin); + opacity: 0; + } +} + +.arrow svg { + display: block; + fill: var(--panel); + stroke: var(--border); + stroke-width: 1px; + transform: rotate(180deg); +} + +.name { + font-size: 14px; + font-weight: 500; + margin-bottom: 1rem; +} + +.grid { + display: grid; + grid-template-columns: auto auto 1fr; + gap: 0.5rem 1rem; +} + +.col1 { + font-size: 13px; + font-weight: 500; + color: var(--text-secondary); + padding-top: 0.25rem; +} + +.col2 { + font-size: 13px; +} + +.col3 { + font-size: 13px; + color: var(--text-secondary); + padding-top: 0.25rem; +} diff --git a/docs-ui/src/components/PropsTable/TypePopup.tsx b/docs-ui/src/components/PropsTable/TypePopup.tsx new file mode 100644 index 0000000000..bd0fc5dd76 --- /dev/null +++ b/docs-ui/src/components/PropsTable/TypePopup.tsx @@ -0,0 +1,49 @@ +import { ComplexTypeDef } from '@/utils/propDefs'; +import { Chip } from '../Chip'; +import { + Button, + Dialog, + DialogTrigger, + OverlayArrow, + Popover, +} from 'react-aria-components'; +import styles from './TypePopup.module.css'; + +interface TypePopupProps { + complexType: ComplexTypeDef; + name: string; +} + +export const TypePopup = ({ complexType, name }: TypePopupProps) => { + return ( + + + + + + + + + +
{complexType.name}
+
+ {Object.entries(complexType.properties).map( + ([propName, propDef]) => [ +
+ {propName} + {propDef.required ? '' : '?'} +
, +
+ {propDef.type} +
, +
+ {propDef.description} +
, + ], + )} +
+
+
+
+ ); +}; 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 65% rename from canon-docs/src/components/Sidebar/Sidebar.module.css rename to docs-ui/src/components/Sidebar/Sidebar.module.css index e558621670..75ac541d9f 100644 --- a/canon-docs/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -6,16 +6,11 @@ .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; } } @@ -24,86 +19,6 @@ 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; -} - -.playgroundSection { - position: absolute; -} - -.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; @@ -115,7 +30,6 @@ transition: opacity 150ms 300ms; right: -20px; - &[data-hovering], &[data-scrolling] { opacity: 1; transition-duration: 75ms; @@ -135,3 +49,74 @@ 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; + + &:first-child { + margin-top: 12px; + } +} + +.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..59e297e26e --- /dev/null +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -0,0 +1,104 @@ +'use client'; + +import styles from './Sidebar.module.css'; +import { + components, + overview, + layoutComponents, + coreConcepts, +} 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'; + +const data = [ + { + title: 'Overview', + content: overview, + url: '', + }, + { + title: 'Core Concepts', + content: coreConcepts, + url: '', + }, + { + title: 'Layout Components', + content: layoutComponents, + url: '/components', + }, + { + title: 'Components', + content: components, + url: '/components', + }, +]; + +export const Sidebar = () => { + 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/docs-ui/src/components/StickyHeader/StickyHeader.module.css b/docs-ui/src/components/StickyHeader/StickyHeader.module.css new file mode 100644 index 0000000000..7cfc197f83 --- /dev/null +++ b/docs-ui/src/components/StickyHeader/StickyHeader.module.css @@ -0,0 +1,98 @@ +.stickyHeader { + position: fixed; + top: 0px; + left: 32px; + right: 32px; + z-index: 99999; + background-color: var(--background); + padding: 16px 20px 16px 40px; + display: flex; + justify-content: space-between; + align-items: center; + backdrop-filter: blur(10px); + pointer-events: auto; + isolation: isolate; + transform: translateZ(0); + opacity: 0; + width: calc(100% - 64px); + mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%); + -webkit-mask-image: linear-gradient( + to bottom, + black 0%, + black 80%, + transparent 100% + ); +} + +@media (max-width: 768px) { + .stickyHeader { + display: none; + } +} + +.right { + display: flex; + align-items: center; + gap: 24px; +} + +.name { + font-size: 24px; + color: var(--text-primary); + font-weight: 400; +} + +.version { + font-size: 14px; + color: var(--text-secondary); + font-weight: 500; +} + +.actions { + display: flex; + align-items: center; + gap: 16px; +} + +.versionLinks { + display: flex; + align-items: center; + + a { + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + color: var(--secondary); + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; + border-radius: 48px; + + &:hover { + color: var(--primary); + background-color: var(--action); + } + } +} + +@media (max-width: 768px) { + .stickyHeader { + padding: 12px 16px; + } + + .right { + gap: 16px; + } + + .version { + font-size: 12px; + } +} + +@media (min-width: 768px) { + .stickyHeader { + width: calc(100% - 332px - 40px); + left: 332px; + right: 40px; + } +} diff --git a/docs-ui/src/components/StickyHeader/StickyHeader.tsx b/docs-ui/src/components/StickyHeader/StickyHeader.tsx new file mode 100644 index 0000000000..804d759715 --- /dev/null +++ b/docs-ui/src/components/StickyHeader/StickyHeader.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { motion, useScroll, useTransform, circOut } from 'framer-motion'; +import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; +import { ThemeSelector } from '../Toolbar/theme'; +import { ThemeNameSelector } from '../Toolbar/theme-name'; +import { useCurrentPage } from '@/hooks/useCurrentPage'; +import styles from './StickyHeader.module.css'; + +export const StickyHeader = () => { + const { scrollY } = useScroll(); + const currentPage = useCurrentPage(); + + // Transform scroll position to opacity only + const opacity = useTransform(scrollY, [100, 200], [0, 1], { + clamp: false, + }); + + const yPos = useTransform(scrollY, [200, 500], [-60, 0], { + clamp: true, + ease: circOut, + }); + + return ( + +
{currentPage || 'Backstage UI'}
+
+ + ); +}; 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/Logo.tsx b/docs-ui/src/components/Toolbar/Logo.tsx new file mode 100644 index 0000000000..159244ecc7 --- /dev/null +++ b/docs-ui/src/components/Toolbar/Logo.tsx @@ -0,0 +1,20 @@ +export const Logo = () => { + return ( + + + + + ); +}; 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..f0e58f2edb --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -0,0 +1,96 @@ +.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; +} + +.left { + /* width: 296px; */ + display: flex; + align-items: center; + gap: 0.5rem; + padding-right: 20px; +} + +.right { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-end; +} + +.actions { + display: none; +} + +.version { + display: none; +} + +.versionLinks { + display: flex; + align-items: center; + + a { + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + color: var(--secondary); + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; + border-radius: 48px; + + &:hover { + color: var(--primary); + background-color: var(--action); + } + } +} + +@media (min-width: 600px) { + .actions { + display: flex; + align-items: center; + gap: 1rem; + } +} + +@media (min-width: 768px) { + .toolbar { + right: 40px; + } +} + +@media (min-width: 820px) { + .right { + justify-content: space-between; + } + + .version { + display: flex; + align-items: center; + justify-content: center; + /* background-color: var(--action); */ + border: 1px solid var(--border2); + border-radius: 48px; + padding-inline: 20px; + color: var(--primary); + font-size: 0.875rem; + font-weight: 500; + height: 48px; + } +} + +@media (min-width: 960px) { + .left { + width: 296px; + } +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 0000000000..29570739f8 --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,52 @@ +'use client'; + +import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; +import { motion, useScroll, useTransform } from 'framer-motion'; +import { useRef } from 'react'; +import { Logo } from './Logo'; +import { ThemeSelector } from './theme'; +import { ThemeNameSelector } from './theme-name'; +import styles from './Toolbar.module.css'; + +interface ToolbarProps { + version: string; +} + +export const Toolbar = ({ version }: ToolbarProps) => { + const containerRef = useRef(null); + const { scrollY } = useScroll(); + + // Transform scroll velocity to vertical movement + const y = useTransform(scrollY, [0, 100], [0, -20], { + clamp: false, + }); + + return ( +
+
+ +
+ +
Version {version} - Alpha
+
+ + + +
+
+
+ ); +}; 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/docs-ui/src/components/Toolbar/theme-name.module.css b/docs-ui/src/components/Toolbar/theme-name.module.css new file mode 100644 index 0000000000..1e1943b886 --- /dev/null +++ b/docs-ui/src/components/Toolbar/theme-name.module.css @@ -0,0 +1,110 @@ +.Select { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + height: 3rem; + padding-left: 1.25rem; + padding-right: 1rem; + margin: 0; + outline: 0; + border: 1px solid var(--color-gray-200); + 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(--action); + + &:focus-visible { + outline: 2px solid var(--color-blue); + outline-offset: -1px; + } +} + +.Popup { + box-sizing: border-box; + padding-block: 0.25rem; + border-radius: 0.375rem; + background-color: var(--panel); + color: var(--color-gray-900); + border: 1px solid var(--border); + padding-inline: 0.25rem; + transform-origin: var(--transform-origin); + transition: transform 150ms, opacity 150ms; + + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } + + &[data-side='none'] { + transition: none; + transform: none; + opacity: 1; + } + + @media (prefers-color-scheme: light) { + outline: 1px solid var(--color-gray-200); + box-shadow: 0px 10px 15px -3px var(--color-gray-200), + 0px 4px 6px -4px var(--color-gray-200); + } + + @media (prefers-color-scheme: dark) { + outline: 1px solid var(--color-gray-300); + outline-offset: -1px; + } +} + +.Popup[data-trigger='Select'] { + min-width: var(--trigger-width); + + .ListBox { + display: block; + width: unset; + max-height: inherit; + min-height: unset; + border: none; + + .react-aria-Header { + padding-left: 1.571rem; + } + } + + .Item { + position: relative; + padding: 0 0.571rem 0 1.571rem; + height: 2rem; + display: flex; + align-items: center; + + &[data-focus-visible] { + outline: none; + } + + &[data-selected] { + font-weight: 600; + background: unset; + color: var(--text-color); + + &::before { + content: '✓'; + content: '✓' / ''; + alt: ' '; + position: absolute; + left: 4px; + } + } + + &[data-focused], + &[data-pressed] { + background: var(--bg); + color: var(--primary); + cursor: pointer; + } + } +} diff --git a/docs-ui/src/components/Toolbar/theme-name.tsx b/docs-ui/src/components/Toolbar/theme-name.tsx new file mode 100644 index 0000000000..544c345f86 --- /dev/null +++ b/docs-ui/src/components/Toolbar/theme-name.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { + Button, + ListBox, + ListBoxItem, + Popover, + Select, + SelectValue, +} from 'react-aria-components'; +import styles from './theme-name.module.css'; +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' }, +]; + +export const ThemeNameSelector = () => { + const { selectedThemeName, setSelectedThemeName } = usePlayground(); + + return ( + + ); +}; 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/docs-ui/src/content/components/button-icon.mdx b/docs-ui/src/content/components/button-icon.mdx new file mode 100644 index 0000000000..e1f27e0601 --- /dev/null +++ b/docs-ui/src/content/components/button-icon.mdx @@ -0,0 +1,85 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { ButtonIconSnippet } from '@/snippets/stories-snippets'; +import { + buttonIconPropDefs, + buttonIconUsageSnippet, + buttonIconDefaultSnippet, + buttonIconVariantsSnippet, + buttonIconSizesSnippet, + buttonIconDisabledSnippet, + buttonIconResponsiveSnippet, + buttonIconAsLinkSnippet, +} from './button-icon.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={buttonIconDefaultSnippet} +/> + +## Usage + + + +## API reference + + + +## Examples + +### Variants + +Here's a view when buttons have different variants. + +} + code={buttonIconVariantsSnippet} +/> + +### Sizes + +Here's a view when buttons have different sizes. + +} + code={buttonIconSizesSnippet} +/> + +### Disabled + +Here's a view when buttons are disabled. + +} + code={buttonIconDisabledSnippet} +/> + +### Responsive + +Here's a view when buttons are responsive. + + + + + + diff --git a/docs-ui/src/content/components/button-icon.props.ts b/docs-ui/src/content/components/button-icon.props.ts new file mode 100644 index 0000000000..2ba7372a9c --- /dev/null +++ b/docs-ui/src/content/components/button-icon.props.ts @@ -0,0 +1,59 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const buttonIconPropDefs: Record = { + variant: { + type: 'enum', + values: ['primary', 'secondary'], + default: 'primary', + responsive: true, + }, + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'medium', + responsive: true, + }, + icon: { type: 'enum', values: ['ReactNode'], responsive: false }, + isDisabled: { type: 'boolean', default: 'false', responsive: false }, + type: { + type: 'enum', + values: ['button', 'submit', 'reset'], + default: 'button', + responsive: false, + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const buttonIconUsageSnippet = `import { ButtonIcon } from '@backstage/ui'; + +`; + +export const buttonIconDefaultSnippet = ` + } variant="primary" /> + } variant="secondary" /> +`; + +export const buttonIconVariantsSnippet = ` + } variant="primary" /> + } variant="secondary" /> +`; + +export const buttonIconSizesSnippet = ` + } size="small" /> + } size="medium" /> +`; + +export const buttonIconDisabledSnippet = `} isDisabled />`; + +export const buttonIconResponsiveSnippet = `} variant={{ initial: 'primary', lg: 'secondary' }} />`; + +export const buttonIconAsLinkSnippet = `import { ButtonLink } from '@backstage/ui'; + + + Button +`; diff --git a/docs-ui/src/content/components/button-link.mdx b/docs-ui/src/content/components/button-link.mdx new file mode 100644 index 0000000000..5ce538838d --- /dev/null +++ b/docs-ui/src/content/components/button-link.mdx @@ -0,0 +1,96 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { ButtonLinkSnippet } from '@/snippets/stories-snippets'; +import { + buttonLinkPropDefs, + buttonLinkSnippetUsage, + buttonLinkVariantsSnippet, + buttonLinkSizesSnippet, + buttonLinkIconsSnippet, + buttonLinkDisabledSnippet, + buttonLinkResponsiveSnippet, +} from './button-link.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={buttonLinkVariantsSnippet} +/> + +## Usage + + + +## API reference + + + +## Examples + +### Variants + +Here's a view when buttons have different variants. + +} + code={buttonLinkVariantsSnippet} +/> + +### Sizes + +Here's a view when buttons have different sizes. + +} + code={buttonLinkSizesSnippet} +/> + +### With Icons + +Here's a view when buttons have icons. + +} + code={buttonLinkIconsSnippet} +/> + +### Disabled + +Here's a view when buttons are disabled. + +} + code={buttonLinkDisabledSnippet} +/> + +### Responsive + +Here's a view when buttons are responsive. + + + + + + diff --git a/docs-ui/src/content/components/button-link.props.ts b/docs-ui/src/content/components/button-link.props.ts new file mode 100644 index 0000000000..758d6fd811 --- /dev/null +++ b/docs-ui/src/content/components/button-link.props.ts @@ -0,0 +1,73 @@ +import { classNamePropDefs, stylePropDefs } from '../../utils/propDefs'; +import type { PropDef } from '../../utils/propDefs'; + +export const buttonLinkPropDefs: Record = { + variant: { + type: 'enum', + values: ['primary', 'secondary'], + default: 'primary', + responsive: true, + }, + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'medium', + responsive: true, + }, + iconStart: { type: 'enum', values: ['ReactNode'], responsive: false }, + iconEnd: { type: 'enum', values: ['ReactNode'], responsive: false }, + isDisabled: { type: 'boolean', default: 'false', responsive: false }, + href: { type: 'string', responsive: false }, + hrefLang: { type: 'string', responsive: false }, + target: { + type: 'enum', + values: ['HTMLAttributeAnchorTarget'], + default: '_self', + responsive: false, + }, + rel: { type: 'string', responsive: false }, + children: { type: 'enum', values: ['ReactNode'], responsive: false }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const buttonLinkSnippetUsage = `import { ButtonLink } from '@backstage/ui'; + +`; + +export const buttonLinkVariantsSnippet = ` + } variant="primary"> + Button + + } variant="secondary"> + Button + +`; + +export const buttonLinkSizesSnippet = ` + Small + Medium +`; + +export const buttonLinkIconsSnippet = ` + }>Button + }>Button + } + iconEnd={}> + Button + +`; + +export const buttonLinkDisabledSnippet = ` + + Primary + + + Secondary + +`; + +export const buttonLinkResponsiveSnippet = ` + Responsive Button +`; diff --git a/canon-docs/src/content/components/button.mdx b/docs-ui/src/content/components/button.mdx similarity index 68% rename from canon-docs/src/content/components/button.mdx rename to docs-ui/src/content/components/button.mdx index aff74fe60b..a25115012b 100644 --- a/canon-docs/src/content/components/button.mdx +++ b/docs-ui/src/content/components/button.mdx @@ -1,22 +1,25 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; -import { ButtonSnippet } from '@/snippets/stories-snippets'; +import { ButtonSnippet, ButtonLinkSnippet } from '@/snippets/stories-snippets'; import { buttonPropDefs, buttonSnippetUsage, buttonVariantsSnippet, buttonSizesSnippet, buttonIconsSnippet, - buttonFullWidthSnippet, buttonDisabledSnippet, 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 @@ -73,18 +74,6 @@ Here's a view when buttons have icons. code={buttonIconsSnippet} /> -### Full width - -Here's a view when buttons are full width. - -} - code={buttonFullWidthSnippet} -/> - ### Disabled Here's a view when buttons are disabled. @@ -102,3 +91,19 @@ Here's a view when buttons are disabled. Here's a view when buttons are responsive. + +### As Link + +If you want to use a button as a link, please use the `ButtonLink` component. + +} + code={buttonAsLinkSnippet} +/> + + + + diff --git a/canon-docs/src/content/components/button.props.ts b/docs-ui/src/content/components/button.props.ts similarity index 57% rename from canon-docs/src/content/components/button.props.ts rename to docs-ui/src/content/components/button.props.ts index fc833a5f73..4647c20956 100644 --- a/canon-docs/src/content/components/button.props.ts +++ b/docs-ui/src/content/components/button.props.ts @@ -14,11 +14,21 @@ export const buttonPropDefs: Record = { default: 'medium', responsive: true, }, + iconStart: { type: 'enum', values: ['ReactNode'], responsive: false }, + iconEnd: { type: 'enum', values: ['ReactNode'], responsive: false }, + isDisabled: { type: 'boolean', default: 'false', responsive: false }, + children: { type: 'enum', values: ['ReactNode'], responsive: false }, + type: { + type: 'enum', + values: ['button', 'submit', 'reset'], + default: 'button', + responsive: false, + }, ...classNamePropDefs, ...stylePropDefs, }; -export const buttonSnippetUsage = `import { Button } from '@backstage/canon'; +export const buttonSnippetUsage = `import { Button } from '@backstage/ui'; - `; export const buttonSizesSnippet = ` @@ -40,20 +47,16 @@ export const buttonSizesSnippet = ` `; export const buttonIconsSnippet = ` - - - -`; - -export const buttonFullWidthSnippet = ` - + + + `; export const buttonDisabledSnippet = ` - - `; @@ -61,3 +64,9 @@ export const buttonDisabledSnippet = ` export const buttonResponsiveSnippet = ``; + +export const buttonAsLinkSnippet = `import { ButtonLink } from '@backstage/ui'; + + + Button +`; diff --git a/docs-ui/src/content/components/card.mdx b/docs-ui/src/content/components/card.mdx new file mode 100644 index 0000000000..06c3a5bc2e --- /dev/null +++ b/docs-ui/src/content/components/card.mdx @@ -0,0 +1,89 @@ +import { PropsTable } from '@/components/PropsTable'; +import { CardSnippet } from '@/snippets/stories-snippets'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { + cardPropDefs, + cardUsageSnippet, + cardDefaultSnippet, + cardHeaderPropDefs, + cardBodyPropDefs, + cardFooterPropDefs, + cardLongBodySnippet, + cardListRowSnippet, +} from './card.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={cardDefaultSnippet} +/> + +## Usage + + + +## API reference + +### Card + +A card component that can be used to display content in a box. + + + +### CardHeader + +To display a header in a card, use the `CardHeader` component. This will be fixed at the top of the card. + + + +### CardBody + +To display content in a card, use the `CardBody` component. This will automatically fill the card. + + + +### CardFooter + +To display a footer in a card, use the `CardFooter` component. This will be fixed at the bottom of the card. + + + +## Examples + +### With long body + +Here's a view when card has a long body. + +} + code={cardLongBodySnippet} + open +/> + +### With list + +Here's a view when card has a list. + +} + code={cardListRowSnippet} + open +/> + + + + diff --git a/docs-ui/src/content/components/card.props.ts b/docs-ui/src/content/components/card.props.ts new file mode 100644 index 0000000000..70c71bdf56 --- /dev/null +++ b/docs-ui/src/content/components/card.props.ts @@ -0,0 +1,83 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const cardPropDefs: Record = { + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const cardHeaderPropDefs: Record = { + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const cardBodyPropDefs: Record = { + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const cardFooterPropDefs: Record = { + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const cardUsageSnippet = `import { card } from '@backstage/ui'; + + + Header + Body + Footer +`; + +export const cardDefaultSnippet = ` + Header + Body + Footer +`; + +export const cardLongBodySnippet = ` + + Header + + + + This is the first paragraph of a long body text that demonstrates how + the Card component handles extensive content. The card should adjust + accordingly to display all the text properly while maintaining its + structure. + + + Here's a second paragraph that adds more content to our card body. + Having multiple paragraphs helps to visualize how spacing works within + the card component. + + + This third paragraph continues to add more text to ensure we have a + proper demonstration of a card with significant content. This makes it + easier to test scrolling behavior and overall layout when content + exceeds the initial view. + + + + Footer + +`; + +export const cardListRowSnippet = ` + + Header + + + Hello world + Hello world + Hello world + Hello world + ... + + + Footer + +`; diff --git a/canon-docs/src/content/components/checkbox.mdx b/docs-ui/src/content/components/checkbox.mdx similarity index 65% rename from canon-docs/src/content/components/checkbox.mdx rename to docs-ui/src/content/components/checkbox.mdx index ea0ac0fdeb..5770396ebb 100644 --- a/canon-docs/src/content/components/checkbox.mdx +++ b/docs-ui/src/content/components/checkbox.mdx @@ -8,11 +8,14 @@ import { checkboxDefaultSnippet, checkboxVariantsSnippet, } from './checkbox.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Checkbox - -A checkbox component that can be used to trigger actions. + - +## Usage + + ## API reference @@ -44,3 +45,7 @@ Here's a view when checkboxes have different variants. preview={} code={checkboxVariantsSnippet} /> + + + + diff --git a/canon-docs/src/content/components/checkbox.props.ts b/docs-ui/src/content/components/checkbox.props.ts similarity index 98% rename from canon-docs/src/content/components/checkbox.props.ts rename to docs-ui/src/content/components/checkbox.props.ts index 9ffbc2f6f1..c7ee69280e 100644 --- a/canon-docs/src/content/components/checkbox.props.ts +++ b/docs-ui/src/content/components/checkbox.props.ts @@ -46,7 +46,7 @@ export const checkboxPropDefs: Record = { ...stylePropDefs, }; -export const checkboxUsageSnippet = `import { Checkbox } from '@backstage/canon'; +export const checkboxUsageSnippet = `import { Checkbox } from '@backstage/ui'; `; diff --git a/canon-docs/src/content/components/collapsible.mdx b/docs-ui/src/content/components/collapsible.mdx similarity index 76% rename from canon-docs/src/content/components/collapsible.mdx rename to docs-ui/src/content/components/collapsible.mdx index e7b5a72091..948da323fe 100644 --- a/canon-docs/src/content/components/collapsible.mdx +++ b/docs-ui/src/content/components/collapsible.mdx @@ -11,11 +11,14 @@ import { collapsibleTriggerSnippet, collapsibleOpenSnippet, } from './collapsible.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Collapsible - -An avatar component with a fallback for initials. + - +## Usage + + ## API reference @@ -69,3 +66,7 @@ Open the panel by default by setting the `defaultOpen` prop to `true`. preview={} code={collapsibleOpenSnippet} /> + + + + diff --git a/canon-docs/src/content/components/collapsible.props.ts b/docs-ui/src/content/components/collapsible.props.ts similarity index 99% rename from canon-docs/src/content/components/collapsible.props.ts rename to docs-ui/src/content/components/collapsible.props.ts index b4bce6c334..55e80f6689 100644 --- a/canon-docs/src/content/components/collapsible.props.ts +++ b/docs-ui/src/content/components/collapsible.props.ts @@ -42,7 +42,7 @@ export const collapsiblePanelPropDefs: Record = { ...stylePropDefs, }; -export const collapsibleUsageSnippet = `import { Collapsible } from '@backstage/canon'; +export const collapsibleUsageSnippet = `import { Collapsible } from '@backstage/ui'; ( diff --git a/canon-docs/src/content/components/container.mdx b/docs-ui/src/content/components/container.mdx similarity index 65% rename from canon-docs/src/content/components/container.mdx rename to docs-ui/src/content/components/container.mdx index 6c9e49a4bb..05615cb1c2 100644 --- a/canon-docs/src/content/components/container.mdx +++ b/docs-ui/src/content/components/container.mdx @@ -9,12 +9,15 @@ import { containerSimpleSnippet, containerResponsiveSnippet, } from './container.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Container - -The container component let you use our default max-width and center the -content on the page. + - +## Usage + + ## API reference @@ -46,3 +47,7 @@ The Container component also supports responsive values, making it easy to create responsive designs. + + + + diff --git a/canon-docs/src/content/components/container.props.ts b/docs-ui/src/content/components/container.props.ts similarity index 97% rename from canon-docs/src/content/components/container.props.ts rename to docs-ui/src/content/components/container.props.ts index 7d955983b8..a4d23a8495 100644 --- a/canon-docs/src/content/components/container.props.ts +++ b/docs-ui/src/content/components/container.props.ts @@ -11,7 +11,7 @@ export const containerPropDefs: Record = { ...stylePropDefs, }; -export const containerUsageSnippet = `import { Container } from "@backstage/canon"; +export const containerUsageSnippet = `import { Container } from "@backstage/ui"; Hello World!`; diff --git a/canon-docs/src/content/components/flex.mdx b/docs-ui/src/content/components/flex.mdx similarity index 72% rename from canon-docs/src/content/components/flex.mdx rename to docs-ui/src/content/components/flex.mdx index cb3f9cde2c..89cd2e380a 100644 --- a/canon-docs/src/content/components/flex.mdx +++ b/docs-ui/src/content/components/flex.mdx @@ -12,11 +12,15 @@ import { flexAlignSnippet, } from './flex.props'; import { spacingPropDefs } from '@/utils/propDefs'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Flex - -A responsive flex container component for vertical stacking with customizable gaps. + - +## Usage + + ## API reference @@ -60,3 +62,7 @@ The Flex component also supports responsive alignment, making it easy to create responsive designs. + + + + diff --git a/canon-docs/src/content/components/flex.props.ts b/docs-ui/src/content/components/flex.props.ts similarity index 99% rename from canon-docs/src/content/components/flex.props.ts rename to docs-ui/src/content/components/flex.props.ts index 0e4bd7d21c..cc4c2d5a75 100644 --- a/canon-docs/src/content/components/flex.props.ts +++ b/docs-ui/src/content/components/flex.props.ts @@ -26,7 +26,7 @@ export const flexPropDefs: Record = { ...stylePropDefs, }; -export const flexUsageSnippet = `import { Flex } from '@backstage/canon'; +export const flexUsageSnippet = `import { Flex } from '@backstage/ui'; `; diff --git a/canon-docs/src/content/components/grid.mdx b/docs-ui/src/content/components/grid.mdx similarity index 83% rename from canon-docs/src/content/components/grid.mdx rename to docs-ui/src/content/components/grid.mdx index 1de56ddd75..0ffdba6a66 100644 --- a/canon-docs/src/content/components/grid.mdx +++ b/docs-ui/src/content/components/grid.mdx @@ -14,12 +14,15 @@ import { gridResponsiveSnippet, gridStartEndSnippet, } from './grid.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Grid - -A layout component that helps to create simple column-based layouts as well as -more complex ones. + - +## Usage + + ## API reference @@ -91,3 +92,7 @@ responsive designs. The start and end props can be used to position the item in the grid. + + + + diff --git a/canon-docs/src/content/components/grid.props.ts b/docs-ui/src/content/components/grid.props.ts similarity index 99% rename from canon-docs/src/content/components/grid.props.ts rename to docs-ui/src/content/components/grid.props.ts index 339231e4a5..34d89785cc 100644 --- a/canon-docs/src/content/components/grid.props.ts +++ b/docs-ui/src/content/components/grid.props.ts @@ -58,7 +58,7 @@ export const gridItemPropDefs: Record = { ...stylePropDefs, }; -export const gridUsageSnippet = `import { Grid } from '@backstage/canon'; +export const gridUsageSnippet = `import { Grid } from '@backstage/ui'; `; diff --git a/docs-ui/src/content/components/header-page.mdx b/docs-ui/src/content/components/header-page.mdx new file mode 100644 index 0000000000..4589e037a4 --- /dev/null +++ b/docs-ui/src/content/components/header-page.mdx @@ -0,0 +1,40 @@ +import { PropsTable } from '@/components/PropsTable'; +import { CodeBlock } from '@/components/CodeBlock'; +import { Snippet } from '@/components/Snippet'; +import { HeaderPageSnippet } from '@/snippets/stories-snippets'; +import { + propDefs, + usage, + simple, + defaultSnippet, + withTabs, + withBreadcrumbs, + withHeaderPage, +} from './header-page.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={defaultSnippet} +/> + +## Usage + + + +## API reference + + + + + + diff --git a/docs-ui/src/content/components/header-page.props.ts b/docs-ui/src/content/components/header-page.props.ts new file mode 100644 index 0000000000..d287c8baf8 --- /dev/null +++ b/docs-ui/src/content/components/header-page.props.ts @@ -0,0 +1,91 @@ +import { + childrenPropDefs, + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const propDefs: Record = { + title: { + type: 'string', + default: 'Your plugin', + }, + customActions: { + type: 'enum', + values: ['ReactNode'], + }, + menuItems: { + type: 'complex', + complexType: { + name: 'MenuItem[]', + properties: { + label: { + type: 'string', + required: true, + description: 'Display text for the menu item', + }, + value: { + type: 'string', + required: true, + description: 'Unique value for the menu item', + }, + onClick: { + type: '() => void', + required: false, + description: 'Callback function when menu item is clicked', + }, + }, + }, + }, + tabs: { + type: 'complex', + complexType: { + name: 'HeaderTab[]', + properties: { + id: { + type: 'string', + required: true, + description: 'Unique identifier for the tab', + }, + label: { + type: 'string', + required: true, + description: 'Display text for the tab', + }, + href: { + type: 'string', + required: false, + description: 'URL to navigate to when tab is clicked', + }, + matchStrategy: { + type: "'exact' | 'prefix'", + required: false, + description: 'How to match the current route to highlight the tab', + }, + }, + }, + }, + ...childrenPropDefs, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const usage = `import { HeaderPage } from '@backstage/ui'; + +`; + +export const defaultSnippet = `Custom action} +/>`; diff --git a/docs-ui/src/content/components/header.mdx b/docs-ui/src/content/components/header.mdx new file mode 100644 index 0000000000..af4e8010c5 --- /dev/null +++ b/docs-ui/src/content/components/header.mdx @@ -0,0 +1,85 @@ +import { PropsTable } from '@/components/PropsTable'; +import { CodeBlock } from '@/components/CodeBlock'; +import { Snippet } from '@/components/Snippet'; +import { HeaderSnippet } from '@/snippets/stories-snippets'; +import { + propDefs, + usage, + simple, + defaultSnippet, + withTabs, + withBreadcrumbs, + withHeaderPage, +} from './header.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={defaultSnippet} +/> + +## Usage + + + +## API reference + + + +## Examples + +### Simple header + +A simple example of how to use the Header component. + +} + code={simple} + open +/> + +### Header with tabs + +A simple example of how to use the Header component with tabs. All links are using React Router +under the hood and will be active when you are on the corresponding page. + +} +code={withTabs} +open +/> + +### Header with breadcrumbs + +Breacrumbs should appear when you scroll down (and not directly visible as it is in the demo below). + +} + code={withBreadcrumbs} + open +/> + +### Header with HeaderPage + +You can use the `Header` component inside the [HeaderPage](/components/header-page) component to compose your multi-level navigation. + +} + code={withHeaderPage} + open +/> + + + + diff --git a/docs-ui/src/content/components/header.props.ts b/docs-ui/src/content/components/header.props.ts new file mode 100644 index 0000000000..50c5540153 --- /dev/null +++ b/docs-ui/src/content/components/header.props.ts @@ -0,0 +1,218 @@ +import { + childrenPropDefs, + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const propDefs: Record = { + icon: { + type: 'enum', + values: ['ReactNode'], + }, + title: { + type: 'string', + default: 'Your plugin', + }, + titleLink: { + type: 'string', + default: '/', + }, + breadcrumbs: { + type: 'complex', + complexType: { + name: 'Breadcrumb[]', + properties: { + label: { + type: 'string', + required: true, + description: 'Display text for the breadcrumb', + }, + href: { + type: 'string', + required: true, + description: 'URL for the breadcrumb link', + }, + }, + }, + }, + customActions: { + type: 'enum', + values: ['ReactNode'], + }, + menuItems: { + type: 'complex', + complexType: { + name: 'MenuItem[]', + properties: { + label: { + type: 'string', + required: true, + description: 'Display text for the menu item', + }, + value: { + type: 'string', + required: true, + description: 'Unique value for the menu item', + }, + onClick: { + type: '() => void', + required: false, + description: 'Callback function when menu item is clicked', + }, + }, + }, + }, + tabs: { + type: 'complex', + complexType: { + name: 'HeaderTab[]', + properties: { + id: { + type: 'string', + required: true, + description: 'Unique identifier for the tab', + }, + label: { + type: 'string', + required: true, + description: 'Display text for the tab', + }, + href: { + type: 'string', + required: false, + description: 'URL to navigate to when tab is clicked', + }, + matchStrategy: { + type: "'exact' | 'prefix'", + required: false, + description: 'How to match the current route to highlight the tab', + }, + }, + }, + }, + onTabSelectionChange: { + type: 'enum', + values: ['(key: string) => void'], + }, + ...childrenPropDefs, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const usage = `import { Header } from '@backstage/ui'; + +
`; + +export const defaultSnippet = `
+ } /> + } /> + } /> + + } +/>`; + +export const simple = `
+ } /> + } /> + } /> + + } +/>`; + +export const withTabs = ` +
+ } /> + } /> + } /> + + } + tabs={[ + { id: 'overview', label: 'Overview' }, + { id: 'checks', label: 'Checks' }, + { id: 'tracks', label: 'Tracks' }, + { id: 'campaigns', label: 'Campaigns' }, + { id: 'integrations', label: 'Integrations' }, + ]} +/> +`; + +export const withBreadcrumbs = `
`; + +export const withHeaderPage = `
+Custom action} +/>`; diff --git a/canon-docs/src/content/components/icon.mdx b/docs-ui/src/content/components/icon.mdx similarity index 55% rename from canon-docs/src/content/components/icon.mdx rename to docs-ui/src/content/components/icon.mdx index a8c91c783a..91860a7e5e 100644 --- a/canon-docs/src/content/components/icon.mdx +++ b/docs-ui/src/content/components/icon.mdx @@ -7,11 +7,14 @@ import { iconUsageSnippet, iconDefaultSnippet, } from './icon.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Icon - -Icons are used to represent an action or a state. + - +## Usage + + ## API reference + + + + diff --git a/canon-docs/src/content/components/icon.props.ts b/docs-ui/src/content/components/icon.props.ts similarity index 97% rename from canon-docs/src/content/components/icon.props.ts rename to docs-ui/src/content/components/icon.props.ts index 113f9f9c9a..7bec0980f6 100644 --- a/canon-docs/src/content/components/icon.props.ts +++ b/docs-ui/src/content/components/icon.props.ts @@ -18,7 +18,7 @@ export const iconPropDefs: Record = { ...stylePropDefs, }; -export const iconUsageSnippet = `import { Icon } from '@backstage/canon'; +export const iconUsageSnippet = `import { Icon } from '@backstage/ui'; `; diff --git a/docs-ui/src/content/components/link.mdx b/docs-ui/src/content/components/link.mdx new file mode 100644 index 0000000000..e0c1be353f --- /dev/null +++ b/docs-ui/src/content/components/link.mdx @@ -0,0 +1,102 @@ +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, + linkColorsSnippet, + linkRouterSnippet, + linkTruncateSnippet, +} from './link.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={linkDefaultSnippet} +/> + +## Usage + + + +## API reference + + + +## Router Integration + +The `Link` component handles both internal and external navigation. It automatically detects whether the provided URL is internal (relative path) or external (absolute URL with protocol) and renders the appropriate element: + +- **Internal routes**: Uses `react-router-dom`'s `Link` component for client-side navigation +- **External URLs**: Renders a standard `` element for traditional navigation + + + +## 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} +/> + +### Colors + +Here's a view when links have different colors. + +} + code={linkColorsSnippet} +/> + +### Truncate + +The `Link` component has a `truncate` prop that can be used to truncate the text. + +} + code={linkTruncateSnippet} +/> + + + + diff --git a/docs-ui/src/content/components/link.props.ts b/docs-ui/src/content/components/link.props.ts new file mode 100644 index 0000000000..748e64cc15 --- /dev/null +++ b/docs-ui/src/content/components/link.props.ts @@ -0,0 +1,81 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const linkPropDefs: Record = { + href: { + type: 'string', + }, + variant: { + type: 'enum', + values: [ + 'title-large', + 'title-medium', + 'title-small', + 'title-x-small', + 'body-large', + 'body-medium', + 'body-small', + 'body-x-small', + ], + default: 'body-medium', + responsive: true, + }, + weight: { + type: 'enum', + values: ['regular', 'bold'], + default: 'regular', + responsive: true, + }, + color: { + type: 'enum', + values: ['primary', 'secondary', 'danger', 'warning', 'success'], + default: 'primary', + responsive: true, + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const linkUsageSnippet = `import { Link } from '@backstage/ui'; + +Sign up for Backstage`; + +export const linkDefaultSnippet = `Sign up for Backstage`; + +export const linkVariantsSnippet = ` + ... + ... + ... + ... + ... + ... + ... + ... +`; + +export const linkWeightsSnippet = ` + + +`; + +export const linkColorsSnippet = ` + I am primary + I am secondary + I am danger + I am warning + I am success +`; + +export const linkRouterSnippet = `import { Link } from '@backstage/ui'; + +// Internal route +Home + +// External URL +Backstage +`; + +export const linkTruncateSnippet = `...`; diff --git a/canon-docs/src/content/components/menu.mdx b/docs-ui/src/content/components/menu.mdx similarity index 73% rename from canon-docs/src/content/components/menu.mdx rename to docs-ui/src/content/components/menu.mdx index a05cfca34a..c1b67b5034 100644 --- a/canon-docs/src/content/components/menu.mdx +++ b/docs-ui/src/content/components/menu.mdx @@ -13,11 +13,14 @@ import { menuHoverSnippet, menuSubmenuSnippet, } from './menu.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Menu - -A list of actions in a dropdown, enhanced with keyboard navigation. + - +## Usage + + ## API reference @@ -103,3 +88,7 @@ You can nest menus to create a more complex navigation structure. preview={} code={menuSubmenuSnippet} /> + + + + diff --git a/canon-docs/src/content/components/menu.props.ts b/docs-ui/src/content/components/menu.props.ts similarity index 99% rename from canon-docs/src/content/components/menu.props.ts rename to docs-ui/src/content/components/menu.props.ts index 1c43d2e959..2d60987ecf 100644 --- a/canon-docs/src/content/components/menu.props.ts +++ b/docs-ui/src/content/components/menu.props.ts @@ -141,7 +141,7 @@ export const menuItemPropDefs: Record = { ...stylePropDefs, }; -export const menuUsageSnippet = `import { Menu } from '@backstage/canon'; +export const menuUsageSnippet = `import { Menu } from '@backstage/ui'; diff --git a/docs-ui/src/content/components/radio-group.mdx b/docs-ui/src/content/components/radio-group.mdx new file mode 100644 index 0000000000..ab3d28ad81 --- /dev/null +++ b/docs-ui/src/content/components/radio-group.mdx @@ -0,0 +1,104 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { RadioGroupSnippet } from '@/snippets/stories-snippets'; +import { + radioGroupPropDefs, + radioGroupUsageSnippet, + radioGroupDefaultSnippet, + radioGroupDescriptionSnippet, + radioGroupHorizontalSnippet, + radioGroupDisabledSnippet, + radioGroupDisabledSingleSnippet, + radioGroupValidationSnippet, + radioGroupReadOnlySnippet, +} from './radio-group.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; + + + +} + code={radioGroupDefaultSnippet} +/> + +## Usage + + + +## API reference + + + +## Examples + +### Horizontal + +Here's a simple TextField with a description. + +} + code={radioGroupHorizontalSnippet} +/> + +### Disabled + +You can disable the entire radio group by adding the `isDisabled` prop to the `RadioGroup` component. + +} + code={radioGroupDisabledSnippet} +/> + +### Disabled Single radio + +You can disable a single radio by adding the `isDisabled` prop to the `Radio` component. + +} + code={radioGroupDisabledSingleSnippet} +/> + +### Validation + +Here's an example of a radio group with errors. + +} + code={radioGroupValidationSnippet} +/> + +### Read only + +You can make the radio group read only by adding the `isReadOnly` prop to the `RadioGroup` component. + +} + code={radioGroupReadOnlySnippet} +/> + + + + diff --git a/docs-ui/src/content/components/radio-group.props.ts b/docs-ui/src/content/components/radio-group.props.ts new file mode 100644 index 0000000000..3ed08f1053 --- /dev/null +++ b/docs-ui/src/content/components/radio-group.props.ts @@ -0,0 +1,64 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const radioGroupPropDefs: Record = { + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'small', + responsive: true, + }, + label: { + type: 'string', + }, + icon: { + type: 'enum', + values: ['ReactNode'], + }, + description: { + type: 'string', + }, + name: { + type: 'string', + required: true, + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const radioGroupUsageSnippet = `import { RadioGroup } from '@backstage/ui'; + +`; + +export const radioGroupDefaultSnippet = ``; + +export const radioGroupDescriptionSnippet = ``; + +export const radioGroupHorizontalSnippet = ``; + +export const radioGroupDisabledSnippet = ` + Bulbasaur + Charmander + Squirtle +`; + +export const radioGroupDisabledSingleSnippet = ` + Bulbasaur + Charmander + Squirtle +`; + +export const radioGroupValidationSnippet = ` (value === \'charmander\' ? \'Nice try!\' : null)> + Bulbasaur + Charmander + Squirtle +`; + +export const radioGroupReadOnlySnippet = ` + Bulbasaur + Charmander + Squirtle +`; diff --git a/docs-ui/src/content/components/search-field.mdx b/docs-ui/src/content/components/search-field.mdx new file mode 100644 index 0000000000..cc8ae98685 --- /dev/null +++ b/docs-ui/src/content/components/search-field.mdx @@ -0,0 +1,64 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { SearchFieldSnippet } from '@/snippets/stories-snippets'; +import { + searchFieldPropDefs, + searchFieldUsageSnippet, + searchFieldDefaultSnippet, + searchFieldSizesSnippet, + searchFieldDescriptionSnippet, +} from './search-field.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; + + + +} + code={searchFieldDefaultSnippet} +/> + +## Usage + + + +## API reference + + + +## Examples + +### Sizes + +We support two different sizes: `small`, `medium`. + +} + code={searchFieldSizesSnippet} +/> + +### With description + +Here's a simple SearchField with a description. + +} + code={searchFieldDescriptionSnippet} +/> + + + + diff --git a/docs-ui/src/content/components/search-field.props.ts b/docs-ui/src/content/components/search-field.props.ts new file mode 100644 index 0000000000..8abe36eec3 --- /dev/null +++ b/docs-ui/src/content/components/search-field.props.ts @@ -0,0 +1,43 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const searchFieldPropDefs: Record = { + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'small', + responsive: true, + }, + label: { + type: 'string', + }, + icon: { + type: 'enum', + values: ['ReactNode'], + }, + description: { + type: 'string', + }, + name: { + type: 'string', + required: true, + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const searchFieldUsageSnippet = `import { SearchField } from '@backstage/ui'; + +`; + +export const searchFieldDefaultSnippet = ``; + +export const searchFieldSizesSnippet = ` + } /> + } /> +`; + +export const searchFieldDescriptionSnippet = ``; diff --git a/canon-docs/src/content/components/select.mdx b/docs-ui/src/content/components/select.mdx similarity index 64% rename from canon-docs/src/content/components/select.mdx rename to docs-ui/src/content/components/select.mdx index 626f4f1bd0..09a852e871 100644 --- a/canon-docs/src/content/components/select.mdx +++ b/docs-ui/src/content/components/select.mdx @@ -10,12 +10,16 @@ import { selectSizesSnippet, selectDisabledSnippet, selectResponsiveSnippet, + selectIconSnippet, } from './select.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; -# Select - -A common form component for choosing a predefined value in a dropdown menu. + - +## Usage + + ## API reference @@ -44,7 +46,7 @@ Select component with label and description. align="center" py={4} open - preview={} + preview={} code={selectDescriptionSnippet} /> @@ -60,6 +62,19 @@ Here's a view when the selects have different sizes. code={selectSizesSnippet} /> +### With Icon + +Here's a view when the select has an icon. + +} +code={selectIconSnippet} +/> + ### Disabled Here's a view when the select is disabled. @@ -77,3 +92,7 @@ Here's a view when the select is disabled. Here's a view when the select is responsive. + + + + diff --git a/canon-docs/src/content/components/select.props.ts b/docs-ui/src/content/components/select.props.ts similarity index 69% rename from canon-docs/src/content/components/select.props.ts rename to docs-ui/src/content/components/select.props.ts index ef2556d7aa..a93f448bd8 100644 --- a/canon-docs/src/content/components/select.props.ts +++ b/docs-ui/src/content/components/select.props.ts @@ -7,7 +7,6 @@ import { export const selectPropDefs: Record = { label: { type: 'string', - default: 'Select an option', responsive: false, }, description: { @@ -24,6 +23,16 @@ export const selectPropDefs: Record = { values: ['Array<{ value: string, label: string }>'], required: true, }, + placeholder: { + type: 'string', + default: 'Select an item', + responsive: false, + }, + icon: { + type: 'enum', + values: ['ReactNode'], + responsive: false, + }, value: { type: 'string', responsive: false, @@ -32,31 +41,60 @@ export const selectPropDefs: Record = { type: 'string', responsive: false, }, - placeholder: { - type: 'string', - responsive: false, - }, size: { type: 'enum', values: ['small', 'medium'], default: 'medium', responsive: true, }, - onValueChange: { + isOpen: { + type: 'boolean', + responsive: false, + }, + defaultOpen: { + type: 'boolean', + responsive: false, + }, + disabledKeys: { type: 'enum', - values: ['(value: string) => void'], + values: ['string[]'], + responsive: false, + }, + isDisabled: { + type: 'boolean', + responsive: false, + }, + isRequired: { + type: 'boolean', + responsive: false, + }, + isInvalid: { + type: 'boolean', + responsive: false, + }, + selectedKey: { + type: 'string', + responsive: false, + }, + defaultSelectedKey: { + type: 'string', responsive: false, }, onOpenChange: { type: 'enum', - values: ['(open: boolean) => void'], + values: ['(isOpen: boolean) => void'], + responsive: false, + }, + onSelectionChange: { + type: 'enum', + values: ['(key: Key | null) => void'], responsive: false, }, ...classNamePropDefs, ...stylePropDefs, }; -export const selectUsageSnippet = `import { Select } from '@backstage/canon'; +export const selectUsageSnippet = `import { Select } from '@backstage/ui'; } + options={[ ... ]} +/>`; + export const selectSizesSnippet = ` { + selectedKey={pageSize?.toString()} + onSelectionChange={value => { table?.setPageSize(Number(value)); }} - className="canon-DataTablePagination--select" + className="bui-DataTablePagination--select" /> )}
-
- {`${fromCount} - ${toCount} of ${rowCount}`} - + {`${fromCount} - ${toCount} of ${rowCount}`} + table?.previousPage()} - disabled={!table?.getCanPreviousPage()} + isDisabled={!table?.getCanPreviousPage()} icon={} /> - table?.nextPage()} - disabled={!table?.getCanNextPage()} + isDisabled={!table?.getCanNextPage()} icon={} />
diff --git a/packages/canon/src/components/DataTable/Pagination/types.ts b/packages/ui/src/components/DataTable/Pagination/types.ts similarity index 100% rename from packages/canon/src/components/DataTable/Pagination/types.ts rename to packages/ui/src/components/DataTable/Pagination/types.ts diff --git a/packages/ui/src/components/DataTable/Root/DataTableRoot.styles.css b/packages/ui/src/components/DataTable/Root/DataTableRoot.styles.css new file mode 100644 index 0000000000..21b9be4eb8 --- /dev/null +++ b/packages/ui/src/components/DataTable/Root/DataTableRoot.styles.css @@ -0,0 +1,5 @@ +.bui-DataTableRoot { + display: flex; + flex-direction: column; + gap: var(--bui-space-3); +} diff --git a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx b/packages/ui/src/components/DataTable/Root/DataTableRoot.tsx similarity index 92% rename from packages/canon/src/components/DataTable/Root/DataTableRoot.tsx rename to packages/ui/src/components/DataTable/Root/DataTableRoot.tsx index 8207fe4412..2e3f7a7c6d 100644 --- a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx +++ b/packages/ui/src/components/DataTable/Root/DataTableRoot.tsx @@ -38,11 +38,7 @@ const DataTableRoot = forwardRef( return ( -
+
); }, diff --git a/packages/canon/src/components/DataTable/Root/types.ts b/packages/ui/src/components/DataTable/Root/types.ts similarity index 100% rename from packages/canon/src/components/DataTable/Root/types.ts rename to packages/ui/src/components/DataTable/Root/types.ts diff --git a/packages/canon/src/components/DataTable/Table/DataTableTable.tsx b/packages/ui/src/components/DataTable/Table/DataTableTable.tsx similarity index 100% rename from packages/canon/src/components/DataTable/Table/DataTableTable.tsx rename to packages/ui/src/components/DataTable/Table/DataTableTable.tsx diff --git a/packages/canon/src/components/DataTable/Table/types.ts b/packages/ui/src/components/DataTable/Table/types.ts similarity index 100% rename from packages/canon/src/components/DataTable/Table/types.ts rename to packages/ui/src/components/DataTable/Table/types.ts diff --git a/packages/canon/src/components/DataTable/index.ts b/packages/ui/src/components/DataTable/index.ts similarity index 100% rename from packages/canon/src/components/DataTable/index.ts rename to packages/ui/src/components/DataTable/index.ts diff --git a/packages/canon/src/components/DataTable/mocked-columns.tsx b/packages/ui/src/components/DataTable/mocked-columns.tsx similarity index 100% rename from packages/canon/src/components/DataTable/mocked-columns.tsx rename to packages/ui/src/components/DataTable/mocked-columns.tsx diff --git a/packages/canon/src/components/DataTable/mocked-components.ts b/packages/ui/src/components/DataTable/mocked-components.ts similarity index 100% rename from packages/canon/src/components/DataTable/mocked-components.ts rename to packages/ui/src/components/DataTable/mocked-components.ts diff --git a/packages/ui/src/components/FieldError/FieldError.stories.tsx b/packages/ui/src/components/FieldError/FieldError.stories.tsx new file mode 100644 index 0000000000..39714d16d2 --- /dev/null +++ b/packages/ui/src/components/FieldError/FieldError.stories.tsx @@ -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 type { Meta, StoryObj } from '@storybook/react'; +import { TextField, Input, Form } from 'react-aria-components'; +import { FieldError } from './FieldError'; + +const meta = { + title: 'Forms/FieldError', + component: FieldError, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Show error with server validation using Form component +export const WithServerValidation: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// Show error using children +export const WithCustomMessage: Story = { + render: () => ( + + + This is a custom error message. + + ), +}; + +// Show error with render prop function +export const WithRenderProp: Story = { + render: () => ( + 'This field is invalid'} + style={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + }} + > + + + {({ validationErrors }) => + validationErrors.length > 0 ? validationErrors[0] : 'Field is invalid' + } + + + ), +}; diff --git a/packages/ui/src/components/FieldError/FieldError.styles.css b/packages/ui/src/components/FieldError/FieldError.styles.css new file mode 100644 index 0000000000..e69e8637d3 --- /dev/null +++ b/packages/ui/src/components/FieldError/FieldError.styles.css @@ -0,0 +1,7 @@ +.bui-FieldError { + display: inline-block; + 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); +} diff --git a/packages/canon/src/components/Button/Button.props.ts b/packages/ui/src/components/FieldError/FieldError.tsx similarity index 51% rename from packages/canon/src/components/Button/Button.props.ts rename to packages/ui/src/components/FieldError/FieldError.tsx index e363360afa..f216cd6bb8 100644 --- a/packages/canon/src/components/Button/Button.props.ts +++ b/packages/ui/src/components/FieldError/FieldError.tsx @@ -14,28 +14,26 @@ * limitations under the License. */ -import type { PropDef, GetPropDefTypes } from '../../props/prop-def'; +import { forwardRef } from 'react'; +import { + FieldError as AriaFieldError, + type FieldErrorProps, +} from 'react-aria-components'; +import clsx from 'clsx'; /** @public */ -export const buttonPropDefs = { - variant: { - type: 'enum', - values: ['primary', 'secondary'], - className: 'canon-Button--variant', - default: 'primary', - responsive: true, - }, - size: { - type: 'enum', - values: ['small', 'medium'], - className: 'canon-Button--size', - default: 'medium', - responsive: true, - }, -} satisfies { - variant: PropDef<'primary' | 'secondary'>; - size: PropDef<'small' | 'medium'>; -}; +export const FieldError = forwardRef( + (props: FieldErrorProps, ref) => { + const { className, ...rest } = props; -/** @public */ -export type ButtonOwnProps = GetPropDefTypes; + return ( + + ); + }, +); + +FieldError.displayName = 'FieldError'; diff --git a/packages/canon/src/components/Tooltip/index.ts b/packages/ui/src/components/FieldError/index.ts similarity index 95% rename from packages/canon/src/components/Tooltip/index.ts rename to packages/ui/src/components/FieldError/index.ts index cf97688854..5b61f83ace 100644 --- a/packages/canon/src/components/Tooltip/index.ts +++ b/packages/ui/src/components/FieldError/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './Tooltip'; +export * from './FieldError'; diff --git a/packages/canon/src/components/FieldLabel/FieldLabel.stories.tsx b/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx similarity index 100% rename from packages/canon/src/components/FieldLabel/FieldLabel.stories.tsx rename to packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx diff --git a/packages/ui/src/components/FieldLabel/FieldLabel.styles.css b/packages/ui/src/components/FieldLabel/FieldLabel.styles.css new file mode 100644 index 0000000000..2dfc28a49d --- /dev/null +++ b/packages/ui/src/components/FieldLabel/FieldLabel.styles.css @@ -0,0 +1,27 @@ +.bui-FieldLabelWrapper { + display: flex; + flex-direction: column; + margin-bottom: var(--bui-space-3); + gap: var(--bui-space-1); +} + +.bui-FieldLabel { + color: var(--bui-fg-primary); + margin-right: auto; + cursor: pointer; + font-weight: var(--bui-font-weight-regular); + font-size: var(--bui-font-size-2); +} + +.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; +} diff --git a/packages/canon/src/components/FieldLabel/FieldLabel.tsx b/packages/ui/src/components/FieldLabel/FieldLabel.tsx similarity index 76% rename from packages/canon/src/components/FieldLabel/FieldLabel.tsx rename to packages/ui/src/components/FieldLabel/FieldLabel.tsx index 8fee7dffed..df0735389a 100644 --- a/packages/canon/src/components/FieldLabel/FieldLabel.tsx +++ b/packages/ui/src/components/FieldLabel/FieldLabel.tsx @@ -16,31 +16,31 @@ import { Label } from 'react-aria-components'; import { forwardRef } from 'react'; import type { FieldLabelProps } from './types'; +import { useStyles } from '../../hooks/useStyles'; /** @public */ export const FieldLabel = forwardRef( (props: FieldLabelProps, ref) => { const { label, secondaryLabel, description, htmlFor, id, ...rest } = props; + const { classNames } = useStyles('FieldLabel'); + if (!label) return null; return ( -
+
{label && ( -
); diff --git a/packages/canon/src/components/FieldLabel/index.ts b/packages/ui/src/components/FieldLabel/index.ts similarity index 100% rename from packages/canon/src/components/FieldLabel/index.ts rename to packages/ui/src/components/FieldLabel/index.ts diff --git a/packages/canon/src/components/FieldLabel/types.ts b/packages/ui/src/components/FieldLabel/types.ts similarity index 100% rename from packages/canon/src/components/FieldLabel/types.ts rename to packages/ui/src/components/FieldLabel/types.ts diff --git a/packages/canon/src/components/Flex/Flex.props.ts b/packages/ui/src/components/Flex/Flex.props.ts similarity index 95% rename from packages/canon/src/components/Flex/Flex.props.ts rename to packages/ui/src/components/Flex/Flex.props.ts index 97a602b42f..b1d9c019d3 100644 --- a/packages/canon/src/components/Flex/Flex.props.ts +++ b/packages/ui/src/components/Flex/Flex.props.ts @@ -29,19 +29,19 @@ const justifyValues = ['start', 'center', 'end', 'between'] as const; const flexPropDefs = { align: { type: 'enum', - className: 'cu-align', + className: 'bui-align', values: alignValues, responsive: true, }, direction: { type: 'enum', - className: 'cu-fd', + className: 'bui-fd', values: directionValues, responsive: true, }, justify: { type: 'enum', - className: 'cu-jc', + className: 'bui-jc', values: justifyValues, responsive: true, }, diff --git a/packages/canon/src/components/Flex/Flex.stories.tsx b/packages/ui/src/components/Flex/Flex.stories.tsx similarity index 100% rename from packages/canon/src/components/Flex/Flex.stories.tsx rename to packages/ui/src/components/Flex/Flex.stories.tsx diff --git a/packages/canon/src/components/Flex/Flex.tsx b/packages/ui/src/components/Flex/Flex.tsx similarity index 89% rename from packages/canon/src/components/Flex/Flex.tsx rename to packages/ui/src/components/Flex/Flex.tsx index a53e0d28f4..ded4fffffa 100644 --- a/packages/canon/src/components/Flex/Flex.tsx +++ b/packages/ui/src/components/Flex/Flex.tsx @@ -21,6 +21,7 @@ import { flexPropDefs } from './Flex.props'; import { extractProps } from '../../utils/extractProps'; import { gapPropDefs } from '../../props/gap-props'; import { spacingPropDefs } from '../../props/spacing.props'; +import { useStyles } from '../../hooks/useStyles'; /** @public */ export const Flex = forwardRef((props, ref) => { @@ -30,11 +31,12 @@ export const Flex = forwardRef((props, ref) => { ...spacingPropDefs, }; + const { classNames } = useStyles('Flex'); const { className, style } = extractProps(props, propDefs); return createElement('div', { ref, - className: clsx('canon-Flex', className), + className: clsx(classNames.root, className), style, children: props.children, }); diff --git a/packages/canon/src/components/Flex/index.ts b/packages/ui/src/components/Flex/index.ts similarity index 100% rename from packages/canon/src/components/Flex/index.ts rename to packages/ui/src/components/Flex/index.ts diff --git a/packages/canon/src/components/Flex/styles.css b/packages/ui/src/components/Flex/styles.css similarity index 98% rename from packages/canon/src/components/Flex/styles.css rename to packages/ui/src/components/Flex/styles.css index 61fb53d257..96c94ab58a 100644 --- a/packages/canon/src/components/Flex/styles.css +++ b/packages/ui/src/components/Flex/styles.css @@ -14,7 +14,7 @@ * limitations under the License. */ -.canon-Flex { +.bui-Flex { display: flex; /* This helps when using `truncate` on text inside a flex container */ diff --git a/packages/canon/src/components/Flex/types.ts b/packages/ui/src/components/Flex/types.ts similarity index 100% rename from packages/canon/src/components/Flex/types.ts rename to packages/ui/src/components/Flex/types.ts diff --git a/packages/canon/src/components/Grid/Grid.props.ts b/packages/ui/src/components/Grid/Grid.props.ts similarity index 93% rename from packages/canon/src/components/Grid/Grid.props.ts rename to packages/ui/src/components/Grid/Grid.props.ts index a918af6187..b6997cb01b 100644 --- a/packages/canon/src/components/Grid/Grid.props.ts +++ b/packages/ui/src/components/Grid/Grid.props.ts @@ -36,7 +36,7 @@ const columnsValues = [ const gridPropDefs = { columns: { type: 'enum | string', - className: 'cu-columns', + className: 'bui-columns', customProperties: ['--columns'], values: columnsValues, responsive: true, @@ -50,28 +50,28 @@ const gridPropDefs = { const gridItemPropDefs = { colSpan: { type: 'enum | string', - className: 'cu-col-span', + className: 'bui-col-span', customProperties: ['--col-span'], values: columnsValues, responsive: true, }, colEnd: { type: 'enum | string', - className: 'cu-col-end', + className: 'bui-col-end', customProperties: ['--col-end'], values: columnsValues, responsive: true, }, colStart: { type: 'enum | string', - className: 'cu-col-start', + className: 'bui-col-start', customProperties: ['--col-start'], values: columnsValues, responsive: true, }, rowSpan: { type: 'enum | string', - className: 'cu-row-span', + className: 'bui-row-span', customProperties: ['--row-span'], values: columnsValues, responsive: true, diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/ui/src/components/Grid/Grid.stories.tsx similarity index 100% rename from packages/canon/src/components/Grid/Grid.stories.tsx rename to packages/ui/src/components/Grid/Grid.stories.tsx diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/ui/src/components/Grid/Grid.tsx similarity index 87% rename from packages/canon/src/components/Grid/Grid.tsx rename to packages/ui/src/components/Grid/Grid.tsx index 7bb5486a2d..27257c8972 100644 --- a/packages/canon/src/components/Grid/Grid.tsx +++ b/packages/ui/src/components/Grid/Grid.tsx @@ -21,6 +21,7 @@ import { gridItemPropDefs, gridPropDefs } from './Grid.props'; import clsx from 'clsx'; import type { GridItemProps, GridProps } from './types'; import { spacingPropDefs } from '../../props/spacing.props'; +import { useStyles } from '../../hooks/useStyles'; const GridRoot = forwardRef((props, ref) => { const propDefs = { @@ -29,11 +30,13 @@ const GridRoot = forwardRef((props, ref) => { ...spacingPropDefs, }; + const { classNames } = useStyles('Grid'); + const { className, style } = extractProps(props, propDefs); return createElement('div', { ref, - className: clsx('canon-Grid', className), + className: clsx(classNames.root, className), style, children: props.children, }); @@ -44,11 +47,12 @@ const GridItem = forwardRef((props, ref) => { ...gridItemPropDefs, }; + const { classNames } = useStyles('Grid'); const { className, style } = extractProps(props, propDefs); return createElement('div', { ref, - className: clsx('canon-GridItem', className), + className: clsx(classNames.item, className), style, children: props.children, }); diff --git a/packages/canon/src/components/Grid/index.ts b/packages/ui/src/components/Grid/index.ts similarity index 100% rename from packages/canon/src/components/Grid/index.ts rename to packages/ui/src/components/Grid/index.ts diff --git a/packages/canon/src/components/Grid/styles.css b/packages/ui/src/components/Grid/styles.css similarity index 57% rename from packages/canon/src/components/Grid/styles.css rename to packages/ui/src/components/Grid/styles.css index 0bb9267795..e21191ad47 100644 --- a/packages/canon/src/components/Grid/styles.css +++ b/packages/ui/src/components/Grid/styles.css @@ -1,3 +1,3 @@ -.canon-Grid { +.bui-Grid { display: grid; } diff --git a/packages/canon/src/components/Grid/types.ts b/packages/ui/src/components/Grid/types.ts similarity index 100% rename from packages/canon/src/components/Grid/types.ts rename to packages/ui/src/components/Grid/types.ts diff --git a/packages/ui/src/components/Header/Header.stories.tsx b/packages/ui/src/components/Header/Header.stories.tsx new file mode 100644 index 0000000000..302aef9765 --- /dev/null +++ b/packages/ui/src/components/Header/Header.stories.tsx @@ -0,0 +1,523 @@ +/* + * 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 { Header } from './Header'; +import { HeaderBreadcrumb, HeaderMenuItem, HeaderTab } from './types'; +import { Button } from '../Button'; +import { HeaderPage } from '../HeaderPage'; +import { MemoryRouter } from 'react-router-dom'; +import { Container } from '../Container'; +import { Text } from '../Text'; +import { ButtonIcon } from '../ButtonIcon'; +import { + RiHeartLine, + RiEmotionHappyLine, + RiCloudy2Line, +} from '@remixicon/react'; + +const meta = { + title: 'Components/Header', + component: Header, + parameters: { + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const withRouter = (Story: StoryFn) => ( + + + +); + +const tabs: HeaderTab[] = [ + { + id: 'overview', + label: 'Overview', + }, + { + id: 'checks', + label: 'Checks', + }, + { + id: 'tracks', + label: 'Tracks', + }, + { + id: 'campaigns', + label: 'Campaigns', + href: '/campaigns', + }, + { + id: 'integrations', + label: 'Integrations', + href: '/integrations', + }, +]; + +const tabs2: HeaderTab[] = [ + { + id: 'Banana', + label: 'Banana', + }, + { + id: 'Apple', + label: 'Apple', + }, + { + id: 'Orange', + label: 'Orange', + }, +]; + +const breadcrumbs: HeaderBreadcrumb[] = [ + { + label: 'Home', + href: '/', + }, + { + label: 'Dashboard', + href: '/dashboard', + }, + { + label: 'Settings', + href: '/settings', + }, +]; + +const menuItems: HeaderMenuItem[] = [ + { + label: 'Settings', + value: 'settings', + }, + { + label: 'Invite new members', + value: 'invite-new-members', + }, +]; + +// Extract layout decorator as a reusable constant +const layoutDecorator = [ + (Story: StoryFn) => ( + <> +
+
+ + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, + quos. + + +
+ + ), + withRouter, +]; + +export const Default: Story = { + args: {}, + decorators: [withRouter], +}; + +export const WithTabs: Story = { + args: { + tabs, + }, + decorators: [withRouter], +}; + +export const WithOptions: Story = { + args: { + menuItems, + }, + decorators: [withRouter], +}; + +export const WithCustomActions: Story = { + args: {}, + decorators: [withRouter], + render: args => ( +
+ } /> + } /> + } /> + + } + /> + ), +}; + +export const WithAllOptions: Story = { + args: { + title: 'My plugin', + titleLink: '/', + menuItems, + }, + decorators: [withRouter], + render: WithCustomActions.render, +}; + +export const WithBreadcrumbs: Story = { + args: { + breadcrumbs, + tabs, + }, + decorators: [withRouter], +}; + +export const WithAllOptionsAndTabs: Story = { + args: { + ...WithAllOptions.args, + tabs, + }, + decorators: [withRouter], + render: WithAllOptions.render, +}; + +export const WithHeaderPage: Story = { + args: { + ...WithAllOptionsAndTabs.args, + }, + decorators: [withRouter], + render: args => ( + <> +
+ } /> + } /> + } /> + + } + /> + Custom action} + /> + + ), +}; + +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..ee75eff639 --- /dev/null +++ b/packages/ui/src/components/Header/HeaderToolbar.tsx @@ -0,0 +1,204 @@ +/* + * 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 { useNavigate, useHref } from 'react-router-dom'; +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; +import { useGSAP } from '@gsap/react'; + +gsap.registerPlugin(ScrollTrigger); + +/** + * 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(); + + // Refs for collision detection + const toolbarWrapperRef = useRef(null); + const toolbarContentRef = useRef(null); + const toolbarControlsRef = useRef(null); + const breadcrumbsRef = 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(); + }; + }, []); + + useGSAP(() => { + gsap.to(breadcrumbsRef.current, { + scrollTrigger: { + start: '10% 10%', + end: '20% 20%', + scrub: true, + }, + opacity: 1, + duration: 1, + ease: 'power2.inOut', + }); + }); + + 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..9ad3f3e472 --- /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..796b0921ad 100644 --- a/packages/canon/src/components/Menu/Combobox.tsx +++ b/packages/ui/src/components/Menu/Combobox.tsx @@ -19,7 +19,6 @@ import { useState, useMemo, useCallback, - useId, ChangeEvent, KeyboardEvent, useRef, @@ -27,7 +26,8 @@ import { } from 'react'; import clsx from 'clsx'; import { MenuComboboxOption, MenuComboboxProps } from './types'; -import { Icon } from '@backstage/canon'; +import { Icon } from '../..'; +import { useId } from 'react-aria'; 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/ui/src/components/RadioGroup/RadioGroup.stories.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx new file mode 100644 index 0000000000..4f28e04bfc --- /dev/null +++ b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx @@ -0,0 +1,147 @@ +/* + * 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 { RadioGroup, Radio } from './RadioGroup'; + +const meta = { + title: 'Forms/RadioGroup', + component: RadioGroup, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + label: 'What is your favorite pokemon?', + }, + render: args => ( + + Bulbasaur + Charmander + Squirtle + + ), +}; + +export const Horizontal: Story = { + args: { + ...Default.args, + orientation: 'horizontal', + }, + render: args => ( + + Bulbasaur + Charmander + Squirtle + + ), +}; + +export const Disabled: Story = { + args: { + ...Default.args, + isDisabled: true, + }, + render: args => ( + + Bulbasaur + Charmander + Squirtle + + ), +}; + +export const DisabledSingle: Story = { + args: { + ...Default.args, + }, + render: args => ( + + Bulbasaur + + Charmander + + Squirtle + + ), +}; + +export const DisabledAndSelected: Story = { + args: { + ...Default.args, + value: 'charmander', + }, + render: args => ( + + Bulbasaur + + Charmander + + Squirtle + + ), +}; + +export const Invalid: Story = { + args: { + ...Default.args, + name: 'pokemon', + isInvalid: true, + }, + render: args => ( + + Bulbasaur + + Charmander + + Squirtle + + ), +}; + +export const Validation: Story = { + args: { + ...Default.args, + name: 'pokemon', + defaultValue: 'charmander', + validationBehavior: 'aria', + validate: value => (value === 'charmander' ? 'Nice try!' : null), + }, + render: args => ( + + Bulbasaur + Charmander + Squirtle + + ), +}; + +export const ReadOnly: Story = { + args: { + ...Default.args, + isReadOnly: true, + defaultValue: 'charmander', + }, + render: args => ( + + Bulbasaur + Charmander + Squirtle + + ), +}; 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/ui/src/components/RadioGroup/RadioGroup.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.tsx new file mode 100644 index 0000000000..4363477c1a --- /dev/null +++ b/packages/ui/src/components/RadioGroup/RadioGroup.tsx @@ -0,0 +1,95 @@ +/* + * 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 { + RadioGroup as AriaRadioGroup, + Radio as AriaRadio, +} from 'react-aria-components'; +import clsx from 'clsx'; +import { FieldLabel } from '../FieldLabel'; +import { FieldError } from '../FieldError'; +import { useStyles } from '../../hooks/useStyles'; + +import type { RadioGroupProps, RadioProps } from './types'; + +/** @public */ +export const RadioGroup = forwardRef( + (props, ref) => { + const { + className, + label, + secondaryLabel, + description, + isRequired, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + children, + ...rest + } = props; + + const { classNames } = useStyles('RadioGroup'); + + useEffect(() => { + if (!label && !ariaLabel && !ariaLabelledBy) { + console.warn( + 'RadioGroup 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 ( + + +
{children}
+ +
+ ); + }, +); + +RadioGroup.displayName = 'RadioGroup'; + +/** @public */ +export const Radio = forwardRef((props, ref) => { + const { className, ...rest } = props; + + const { classNames } = useStyles('RadioGroup'); + + return ( + + ); +}); + +RadioGroup.displayName = 'RadioGroup'; diff --git a/packages/ui/src/components/RadioGroup/index.ts b/packages/ui/src/components/RadioGroup/index.ts new file mode 100644 index 0000000000..fd9572f667 --- /dev/null +++ b/packages/ui/src/components/RadioGroup/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 * from './RadioGroup'; +export * from './types'; diff --git a/packages/ui/src/components/RadioGroup/types.ts b/packages/ui/src/components/RadioGroup/types.ts new file mode 100644 index 0000000000..029ef4baf9 --- /dev/null +++ b/packages/ui/src/components/RadioGroup/types.ts @@ -0,0 +1,32 @@ +/* + * 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 { + RadioGroupProps as AriaRadioGroupProps, + RadioProps as AriaRadioProps, +} from 'react-aria-components'; +import type { FieldLabelProps } from '../FieldLabel/types'; +import { ReactNode } from 'react'; + +/** @public */ +export interface RadioGroupProps + extends Omit, + Omit { + children?: ReactNode; +} + +/** @public */ +export interface RadioProps extends AriaRadioProps {} 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/ui/src/components/SearchField/index.ts b/packages/ui/src/components/SearchField/index.ts new file mode 100644 index 0000000000..288c3fe44a --- /dev/null +++ b/packages/ui/src/components/SearchField/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 * 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 81% rename from packages/canon/src/components/Select/Select.stories.tsx rename to packages/ui/src/components/Select/Select.stories.tsx index 000ba180dc..a8191d9604 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,43 @@ export const Preview: Story = { }, }; -export const WithDescription: Story = { +export const WithLabel: Story = { args: { - ...Preview.args, + ...Default.args, + label: 'Font Family', + }, +}; + +export const WithFullWidth: Story = { + args: { + ...Default.args, + label: 'Font Family', + style: { width: '100%' }, + }, +}; + +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 +312,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..2cbadfda32 --- /dev/null +++ b/packages/ui/src/components/Select/Select.styles.css @@ -0,0 +1,176 @@ +/* + * 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; + cursor: pointer; + gap: var(--bui-space-2); + width: 100%; + + & svg { + flex-shrink: 0; + color: var(--bui-fg-secondary); + } + + &[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 { + transition: border-color 0.2s ease-in-out, outline-color 0.2s ease-in-out; + 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); + text-align: left; + + & .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-left: var(--bui-space-3); + padding-right: 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-1); + 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..d404b39e1a --- /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( + 'Select 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/ui/src/components/Skeleton/index.tsx b/packages/ui/src/components/Skeleton/index.tsx new file mode 100644 index 0000000000..f1e76b1851 --- /dev/null +++ b/packages/ui/src/components/Skeleton/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 { 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..a0a1fa75dc --- /dev/null +++ b/packages/ui/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,457 @@ +/* + * 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/ui/src/components/Tabs/index.ts b/packages/ui/src/components/Tabs/index.ts new file mode 100644 index 0000000000..38a6f20ea7 --- /dev/null +++ b/packages/ui/src/components/Tabs/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { 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 94% rename from packages/canon/src/components/TextField/TextField.stories.tsx rename to packages/ui/src/components/TextField/TextField.stories.tsx index e07aa6ea05..7adc84e909 100644 --- a/packages/canon/src/components/TextField/TextField.stories.tsx +++ b/packages/ui/src/components/TextField/TextField.stories.tsx @@ -40,7 +40,7 @@ type Story = StoryObj; export const Default: Story = { args: { name: 'url', - defaultValue: 'Enter a URL', + placeholder: 'Enter a URL', style: { maxWidth: '300px', }, @@ -97,9 +97,15 @@ export const Disabled: Story = { export const WithIcon: Story = { args: { ...Default.args, - defaultValue: '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 76% rename from packages/canon/src/components/TextField/TextField.tsx rename to packages/ui/src/components/TextField/TextField.tsx index 444e76e983..2756c3c85f 100644 --- a/packages/canon/src/components/TextField/TextField.tsx +++ b/packages/ui/src/components/TextField/TextField.tsx @@ -15,16 +15,13 @@ */ import { forwardRef, useEffect } from 'react'; -import { - Input, - TextField as AriaTextField, - FieldError, -} from 'react-aria-components'; -import { useResponsiveValue } from '../../hooks/useResponsiveValue'; +import { Input, TextField as AriaTextField } from 'react-aria-components'; 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( @@ -39,6 +36,7 @@ export const TextField = forwardRef( isRequired, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, + placeholder, ...rest } = props; @@ -50,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 = @@ -59,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 92% rename from packages/canon/src/components/TextField/types.ts rename to packages/ui/src/components/TextField/types.ts index 92fa077389..75a5c68aaa 100644 --- a/packages/canon/src/components/TextField/types.ts +++ b/packages/ui/src/components/TextField/types.ts @@ -33,4 +33,9 @@ export interface TextFieldProps * @defaultValue 'medium' */ size?: 'small' | 'medium' | Partial>; + + /** + * Text to display in the input when it has no value + */ + placeholder?: string; } 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 80% rename from packages/canon/src/css/components.css rename to packages/ui/src/css/components.css index c85c1bbdd9..268bbe40dd 100644 --- a/packages/canon/src/css/components.css +++ b/packages/ui/src/css/components.css @@ -17,19 +17,24 @@ @import '../components/Avatar/Avatar.styles.css'; @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'; @import '../components/DataTable/Root/DataTableRoot.styles.css'; @import '../components/DataTable/Pagination/DataTablePagination.styles.css'; +@import '../components/FieldError/FieldError.styles.css'; @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/IconButton/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'; @import '../components/Table/TableCellText/TableCellText.styles.css'; @@ -38,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..30d1c93d23 --- /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', 'tertiary'] 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..2f970972f1 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,76 @@ # @backstage/plugin-api-docs +## 0.12.10-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/plugin-catalog@1.31.2-next.1 + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + +## 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..71cd769325 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.1", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/api-docs/report-alpha.api.md b/plugins/api-docs/report-alpha.api.md index b13fca4996..c383ea810c 100644 --- a/plugins/api-docs/report-alpha.api.md +++ b/plugins/api-docs/report-alpha.api.md @@ -6,11 +6,13 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityCardType } from '@backstage/plugin-catalog-react/alpha'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; @@ -73,9 +75,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'entity-card:api-docs/consumed-apis': ExtensionDefinition<{ kind: 'entity-card'; diff --git a/plugins/api-docs/src/alpha.tsx b/plugins/api-docs/src/alpha.tsx index 356328a61d..4ff73f0e26 100644 --- a/plugins/api-docs/src/alpha.tsx +++ b/plugins/api-docs/src/alpha.tsx @@ -20,7 +20,6 @@ import { ApiBlueprint, NavItemBlueprint, PageBlueprint, - createApiFactory, createFrontendPlugin, } from '@backstage/frontend-plugin-api'; @@ -55,8 +54,8 @@ const apiDocsNavItem = NavItemBlueprint.make({ const apiDocsConfigApi = ApiBlueprint.make({ name: 'config', - params: { - factory: createApiFactory({ + params: define => + define({ api: apiDocsConfigRef, deps: {}, factory: () => { @@ -68,7 +67,6 @@ const apiDocsConfigApi = ApiBlueprint.make({ }; }, }), - }, }); const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({ diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 14a64c0fca..fb427cde4d 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-app-backend +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config-loader@1.10.2 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.36-next.0 + +## 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..0094df6cc3 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.5-next.0", "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..315559cd0a 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-app-node +## 0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config-loader@1.10.2 + +## 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..beac2d174a 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.36-next.0", "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..a3f5c52010 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-app-visualizer +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + +## 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..e734faad3b 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.22-next.0", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index 528736c655..f1214e3e04 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/plugin-app +## 0.2.0-next.0 + +### Minor Changes + +- 29786f6: Updated the `app/nav` extension to use the new `NavContentBlueprint`, and removed support for extensions created with the now removed `NavLogoBlueprint`. + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration-react@1.2.9 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.36 + +## 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..199054f141 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.2.0-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "app", diff --git a/plugins/app/report.api.md b/plugins/app/report.api.md index 3654a3965a..15001d2961 100644 --- a/plugins/app/report.api.md +++ b/plugins/app/report.api.md @@ -6,16 +6,19 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { AppTheme } from '@backstage/frontend-plugin-api'; import { ComponentRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; import { IconComponent as IconComponent_2 } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; +import { NavContentComponent } from '@backstage/frontend-plugin-api'; import { ReactNode } from 'react'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { SignInPageProps } from '@backstage/core-plugin-api'; @@ -100,13 +103,10 @@ const appPlugin: FrontendPlugin< optional: false; } >; - logos: ExtensionInput< + content: ExtensionInput< ConfigurableExtensionDataRef< - { - logoIcon?: JSX.Element; - logoFull?: JSX.Element; - }, - 'core.nav-logo.logo-elements', + NavContentComponent, + 'core.nav-content.component', {} >, { @@ -224,9 +224,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/analytics': ExtensionDefinition<{ kind: 'api'; @@ -239,9 +243,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/app-language': ExtensionDefinition<{ kind: 'api'; @@ -254,9 +262,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/app-theme': ExtensionDefinition<{ config: {}; @@ -277,9 +289,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'app-theme'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/atlassian-auth': ExtensionDefinition<{ kind: 'api'; @@ -292,9 +308,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/bitbucket-auth': ExtensionDefinition<{ kind: 'api'; @@ -307,9 +327,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/bitbucket-server-auth': ExtensionDefinition<{ kind: 'api'; @@ -322,9 +346,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/components': ExtensionDefinition<{ config: {}; @@ -352,9 +380,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'components'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/dialog': ExtensionDefinition<{ kind: 'api'; @@ -367,9 +399,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/discovery': ExtensionDefinition<{ kind: 'api'; @@ -382,9 +418,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/error': ExtensionDefinition<{ kind: 'api'; @@ -397,9 +437,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/feature-flags': ExtensionDefinition<{ kind: 'api'; @@ -412,9 +456,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/fetch': ExtensionDefinition<{ kind: 'api'; @@ -427,9 +475,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/github-auth': ExtensionDefinition<{ kind: 'api'; @@ -442,9 +494,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/gitlab-auth': ExtensionDefinition<{ kind: 'api'; @@ -457,9 +513,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/google-auth': ExtensionDefinition<{ kind: 'api'; @@ -472,9 +532,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/icons': ExtensionDefinition<{ config: {}; @@ -501,9 +565,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'icons'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/microsoft-auth': ExtensionDefinition<{ kind: 'api'; @@ -516,9 +584,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/oauth-request': ExtensionDefinition<{ kind: 'api'; @@ -531,9 +603,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/okta-auth': ExtensionDefinition<{ kind: 'api'; @@ -546,9 +622,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/onelogin-auth': ExtensionDefinition<{ kind: 'api'; @@ -561,9 +641,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/permission': ExtensionDefinition<{ kind: 'api'; @@ -576,9 +660,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/scm-auth': ExtensionDefinition<{ kind: 'api'; @@ -591,9 +679,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/scm-integrations': ExtensionDefinition<{ kind: 'api'; @@ -606,9 +698,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/storage': ExtensionDefinition<{ kind: 'api'; @@ -621,9 +717,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/translations': ExtensionDefinition<{ config: {}; @@ -655,9 +755,13 @@ const appPlugin: FrontendPlugin< }; kind: 'api'; name: 'translations'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:app/vmware-cloud-auth': ExtensionDefinition<{ kind: 'api'; @@ -670,9 +774,13 @@ const appPlugin: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'app-root-element:app/alert-display': ExtensionDefinition<{ config: { diff --git a/plugins/app/src/defaultApis.ts b/plugins/app/src/defaultApis.ts index 535be78e05..4da28b44a6 100644 --- a/plugins/app/src/defaultApis.ts +++ b/plugins/app/src/defaultApis.ts @@ -39,7 +39,6 @@ import { } from '../../../packages/core-app-api/src/apis/implementations'; import { - createApiFactory, alertApiRef, analyticsApiRef, errorApiRef, @@ -75,18 +74,17 @@ import { DefaultDialogApi } from './apis/DefaultDialogApi'; export const apis = [ ApiBlueprint.make({ name: 'dialog', - params: { - factory: createApiFactory({ + params: define => + define({ api: dialogApiRef, deps: {}, factory: () => new DefaultDialogApi(), }), - }, }), ApiBlueprint.make({ name: 'discovery', - params: { - factory: createApiFactory({ + params: define => + define({ api: discoveryApiRef, deps: { configApi: configApiRef }, factory: ({ configApi }) => @@ -94,32 +92,29 @@ export const apis = [ `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`, ), }), - }, }), ApiBlueprint.make({ name: 'alert', - params: { - factory: createApiFactory({ + params: define => + define({ api: alertApiRef, deps: {}, factory: () => new AlertApiForwarder(), }), - }, }), ApiBlueprint.make({ name: 'analytics', - params: { - factory: createApiFactory({ + params: define => + define({ api: analyticsApiRef, deps: {}, factory: () => new NoOpAnalyticsApi(), }), - }, }), ApiBlueprint.make({ name: 'error', - params: { - factory: createApiFactory({ + params: define => + define({ api: errorApiRef, deps: { alertApi: alertApiRef }, factory: ({ alertApi }) => { @@ -128,22 +123,20 @@ export const apis = [ return errorApi; }, }), - }, }), ApiBlueprint.make({ name: 'storage', - params: { - factory: createApiFactory({ + params: define => + define({ api: storageApiRef, deps: { errorApi: errorApiRef }, factory: ({ errorApi }) => WebStorage.create({ errorApi }), }), - }, }), ApiBlueprint.make({ name: 'fetch', - params: { - factory: createApiFactory({ + params: define => + define({ api: fetchApiRef, deps: { configApi: configApiRef, @@ -164,22 +157,20 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'oauth-request', - params: { - factory: createApiFactory({ + params: define => + define({ api: oauthRequestApiRef, deps: {}, factory: () => new OAuthRequestManager(), }), - }, }), ApiBlueprint.make({ name: 'google-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: googleAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -194,12 +185,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'microsoft-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: microsoftAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -214,12 +204,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'github-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: githubAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -235,12 +224,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'okta-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: oktaAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -255,12 +243,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'gitlab-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: gitlabAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -275,12 +262,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'onelogin-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: oneloginAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -295,12 +281,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'bitbucket-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: bitbucketAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -316,12 +301,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'bitbucket-server-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: bitbucketServerAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -337,12 +321,11 @@ export const apis = [ environment: configApi.getOptionalString('auth.environment'), }), }), - }, }), ApiBlueprint.make({ name: 'atlassian-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: atlassianAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -358,12 +341,11 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'vmware-cloud-auth', - params: { - factory: createApiFactory({ + params: define => + define({ api: vmwareCloudAuthApiRef, deps: { discoveryApi: discoveryApiRef, @@ -379,12 +361,11 @@ export const apis = [ }); }, }), - }, }), ApiBlueprint.make({ name: 'permission', - params: { - factory: createApiFactory({ + params: define => + define({ api: permissionApiRef, deps: { discovery: discoveryApiRef, @@ -394,22 +375,18 @@ export const apis = [ factory: ({ config, discovery, identity }) => IdentityPermissionApi.create({ config, discovery, identity }), }), - }, }), ApiBlueprint.make({ name: 'scm-auth', - params: { - factory: ScmAuth.createDefaultApiFactory(), - }, + params: define => define(ScmAuth.createDefaultApiFactory()), }), ApiBlueprint.make({ name: 'scm-integrations', - params: { - factory: createApiFactory({ + params: define => + define({ api: scmIntegrationsApiRef, deps: { configApi: configApiRef }, factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), }), - }, }), ] as const; diff --git a/plugins/app/src/extensions/AppLanguageApi.ts b/plugins/app/src/extensions/AppLanguageApi.ts index 7a6c10db96..96d19a578a 100644 --- a/plugins/app/src/extensions/AppLanguageApi.ts +++ b/plugins/app/src/extensions/AppLanguageApi.ts @@ -17,14 +17,14 @@ // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppLanguageSelector } from '../../../../packages/core-app-api/src/apis/implementations/AppLanguageApi'; import { appLanguageApiRef } from '@backstage/core-plugin-api/alpha'; -import { ApiBlueprint, createApiFactory } from '@backstage/frontend-plugin-api'; +import { ApiBlueprint } from '@backstage/frontend-plugin-api'; export const AppLanguageApi = ApiBlueprint.make({ name: 'app-language', - params: { - factory: createApiFactory( - appLanguageApiRef, - AppLanguageSelector.createWithStorage(), - ), - }, + params: define => + define({ + api: appLanguageApiRef, + deps: {}, + factory: () => AppLanguageSelector.createWithStorage(), + }), }); diff --git a/plugins/app/src/extensions/AppNav.tsx b/plugins/app/src/extensions/AppNav.tsx index eaec264dca..aa030300fe 100644 --- a/plugins/app/src/extensions/AppNav.tsx +++ b/plugins/app/src/extensions/AppNav.tsx @@ -18,93 +18,93 @@ import { createExtension, coreExtensionData, createExtensionInput, - useRouteRef, NavItemBlueprint, - NavLogoBlueprint, + NavContentBlueprint, + NavContentComponentProps, + routeResolutionApiRef, + IconComponent, + RouteRef, + useApi, + NavContentComponent, } from '@backstage/frontend-plugin-api'; -import { makeStyles } from '@material-ui/core/styles'; -import { - Sidebar, - useSidebarOpenState, - Link, - sidebarConfig, - SidebarDivider, - SidebarItem, -} from '@backstage/core-components'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import LogoIcon from '../../../../packages/app/src/components/Root/LogoIcon'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import LogoFull from '../../../../packages/app/src/components/Root/LogoFull'; - -const useSidebarLogoStyles = makeStyles({ - root: { - width: sidebarConfig.drawerWidthClosed, - height: 3 * sidebarConfig.logoHeight, - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center', - marginBottom: -14, - }, - link: { - width: sidebarConfig.drawerWidthClosed, - marginLeft: 24, - }, -}); - -const SidebarLogo = ( - props: (typeof NavLogoBlueprint.dataRefs.logoElements)['T'], -) => { - const classes = useSidebarLogoStyles(); - const { isOpen } = useSidebarOpenState(); +import { Sidebar, SidebarItem } from '@backstage/core-components'; +import { useMemo } from 'react'; +function DefaultNavContent(props: NavContentComponentProps) { return ( -
- - {isOpen - ? props?.logoFull ?? - : props?.logoIcon ?? } - -
+ + {props.items.map((item, index) => ( + + ))} + ); -}; +} -const SidebarNavItem = ( - props: (typeof NavItemBlueprint.dataRefs.target)['T'], -) => { - const { icon: Icon, title, routeRef } = props; - const link = useRouteRef(routeRef); - if (!link) { - return null; - } - // TODO: Support opening modal, for example, the search one - return ; -}; +// This helps defer rendering until the app is being rendered, which is needed +// because the RouteResolutionApi can't be called until the app has been fully initialized. +function NavContentRenderer(props: { + Content: NavContentComponent; + items: Array<{ + title: string; + icon: IconComponent; + routeRef: RouteRef; + }>; +}) { + const routeResolutionApi = useApi(routeResolutionApiRef); + + const items = useMemo(() => { + return props.items.flatMap(item => { + const link = routeResolutionApi.resolve(item.routeRef); + if (!link) { + // eslint-disable-next-line no-console + console.warn( + `NavItemBlueprint: unable to resolve route ref ${item.routeRef}`, + ); + return []; + } + return [ + { + to: link(), + text: item.title, + icon: item.icon, + title: item.title, + routeRef: item.routeRef, + }, + ]; + }); + }, [props.items, routeResolutionApi]); + + return ; +} export const AppNav = createExtension({ name: 'nav', attachTo: { id: 'app/layout', input: 'nav' }, inputs: { items: createExtensionInput([NavItemBlueprint.dataRefs.target]), - logos: createExtensionInput([NavLogoBlueprint.dataRefs.logoElements], { + content: createExtensionInput([NavContentBlueprint.dataRefs.component], { singleton: true, optional: true, }), }, output: [coreExtensionData.reactElement], - factory: ({ inputs }) => [ - coreExtensionData.reactElement( - - - - {inputs.items.map((item, index) => ( - - ))} - , - ), - ], + *factory({ inputs }) { + const Content = + inputs.content?.get(NavContentBlueprint.dataRefs.component) ?? + DefaultNavContent; + + yield coreExtensionData.reactElement( + + item.get(NavItemBlueprint.dataRefs.target), + )} + Content={Content} + />, + ); + }, }); 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/app/src/extensions/AppThemeApi.tsx b/plugins/app/src/extensions/AppThemeApi.tsx index 2d35a50cd5..670c4504c6 100644 --- a/plugins/app/src/extensions/AppThemeApi.tsx +++ b/plugins/app/src/extensions/AppThemeApi.tsx @@ -24,7 +24,6 @@ import { createExtensionInput, ThemeBlueprint, ApiBlueprint, - createApiFactory, appThemeApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -41,14 +40,16 @@ export const AppThemeApi = ApiBlueprint.makeWithOverrides({ }), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - appThemeApiRef, - AppThemeSelector.createWithStorage( - inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)), - ), - ), - }); + return originalFactory(define => + define({ + api: appThemeApiRef, + deps: {}, + factory: () => + AppThemeSelector.createWithStorage( + inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)), + ), + }), + ); }, }); diff --git a/plugins/app/src/extensions/ComponentsApi.tsx b/plugins/app/src/extensions/ComponentsApi.tsx index b578429253..fa14d28b10 100644 --- a/plugins/app/src/extensions/ComponentsApi.tsx +++ b/plugins/app/src/extensions/ComponentsApi.tsx @@ -18,7 +18,6 @@ import { createComponentExtension, createExtensionInput, ApiBlueprint, - createApiFactory, componentsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -36,15 +35,17 @@ export const ComponentsApi = ApiBlueprint.makeWithOverrides({ ), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - componentsApiRef, - DefaultComponentsApi.fromComponents( - inputs.components.map(i => - i.get(createComponentExtension.componentDataRef), + return originalFactory(define => + define({ + api: componentsApiRef, + deps: {}, + factory: () => + DefaultComponentsApi.fromComponents( + inputs.components.map(i => + i.get(createComponentExtension.componentDataRef), + ), ), - ), - ), - }); + }), + ); }, }); diff --git a/plugins/app/src/extensions/FeatureFlagsApi.ts b/plugins/app/src/extensions/FeatureFlagsApi.ts index 40a44d1348..1a2eff0084 100644 --- a/plugins/app/src/extensions/FeatureFlagsApi.ts +++ b/plugins/app/src/extensions/FeatureFlagsApi.ts @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, featureFlagsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -27,12 +26,11 @@ import { LocalStorageFeatureFlags } from '../../../../packages/core-app-api/src/ */ export const FeatureFlagsApi = ApiBlueprint.make({ name: 'feature-flags', - params: { - // TODO: properly discovery feature flags, maybe rework the whole thing - factory: createApiFactory({ + params: define => + define({ + // TODO: properly discovery feature flags, maybe rework the whole thing api: featureFlagsApiRef, deps: {}, factory: () => new LocalStorageFeatureFlags(), }), - }, }); diff --git a/plugins/app/src/extensions/IconsApi.ts b/plugins/app/src/extensions/IconsApi.ts index e73a74132a..9457652870 100644 --- a/plugins/app/src/extensions/IconsApi.ts +++ b/plugins/app/src/extensions/IconsApi.ts @@ -18,7 +18,6 @@ import { createExtensionInput, IconBundleBlueprint, ApiBlueprint, - createApiFactory, iconsApiRef, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -37,15 +36,17 @@ export const IconsApi = ApiBlueprint.makeWithOverrides({ }), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory( - iconsApiRef, - new DefaultIconsApi( - inputs.icons - .map(i => i.get(IconBundleBlueprint.dataRefs.icons)) - .reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons), - ), - ), - }); + return originalFactory(define => + define({ + api: iconsApiRef, + deps: {}, + factory: () => + new DefaultIconsApi( + inputs.icons + .map(i => i.get(IconBundleBlueprint.dataRefs.icons)) + .reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons), + ), + }), + ); }, }); diff --git a/plugins/app/src/extensions/TranslationsApi.tsx b/plugins/app/src/extensions/TranslationsApi.tsx index ed7ab1abdb..d95c333e8b 100644 --- a/plugins/app/src/extensions/TranslationsApi.tsx +++ b/plugins/app/src/extensions/TranslationsApi.tsx @@ -16,7 +16,6 @@ import { ApiBlueprint, TranslationBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { @@ -39,8 +38,8 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({ ), }, factory: (originalFactory, { inputs }) => { - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: translationApiRef, deps: { languageApi: appLanguageApiRef }, factory: ({ languageApi }) => @@ -51,6 +50,6 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({ ), }), }), - }); + ); }, }); diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 5bd8d12ed7..81bdd7ce42 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..01fa23f23e 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.6-next.0", "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..811d5ef23c 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..03c6e9cb28 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.6-next.0", "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..a10e48d26b 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.25.3-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + +## 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..2e92f4b019 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.6-next.0", "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..5baeb7de11 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + +## 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..e88909bf95 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.11-next.0", "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..f985290bc3 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..7009e55ca2 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.6-next.0", "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..c88b9e011d 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..78db7d203e 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.6-next.0", "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..f83942615f 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + +## 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..17a4ac2044 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.6-next.0", "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..63d1a8310f 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 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..4e07ced5c9 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.6-next.0", "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..5e289adb81 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..a89e4ff213 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.6-next.0", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index c7466f1ed2..4bda0b90ec 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..fc0ff796bf 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.6-next.0", "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..da07eb0d82 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..4e43445c5e 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.6-next.0", "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..28218175b5 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + +## 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..576bc46bfa 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.11-next.0", "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..52cbe2a7e5 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..89169e19de 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.6-next.0", "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..7c9fdd934e 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..de18a707f5 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.6-next.0", "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..4804679702 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + +## 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..d039316140 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.11-next.0", "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..75b97535c7 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.25.3-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + +## 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..7f5d39c611 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.6-next.0", "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..11b3702725 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..47894a644a 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.6-next.0", "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..f7487cc35f 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..08a9dfe2f4 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.6-next.0", "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..cb7cab3f2e 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + +## 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..bf391ed8f5 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.6-next.0", "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..8a5230cfc3 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + +## 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..3c7f9041a8 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.6-next.0", "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..4678e0e204 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-auth-backend +## 0.25.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 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..59a663d988 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.3-next.0", "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..af42151b67 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-node +## 0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 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..4485b1b249 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.6-next.0", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index da56041530..f7df9d4b11 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-auth-react +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + +## 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..813399f751 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.18-next.0", "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..8592e6a82a 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 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..adafaa86f4 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.14-next.0", "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..7fd6a18314 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..19c33e8334 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.1", "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..df0da3a397 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + +## 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..6a96b778c4 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.5-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 66e8f9a5c2..ef37f7415d 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..2e18aab8b3 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.2-next.0", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 5bc457524c..4dff9ab044 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..6fb28d6084 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.2-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 1831056e4e..4942805de8 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 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..efdc2911e1 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.11-next.0", "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..1a64c55387 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..60bdd0ec44 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.5-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gitea/CHANGELOG.md b/plugins/catalog-backend-module-gitea/CHANGELOG.md index bea863224c..61b1851616 100644 --- a/plugins/catalog-backend-module-gitea/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-gitea +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..9c8a4e7725 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.3-next.0", "license": "Apache-2.0", "description": "The gitea backend module for the catalog plugin.", "main": "src/index.ts", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 1892a829e4..d55b1b10ff 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-catalog-backend-module-github@0.10.2-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + +## 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..7daefca9ce 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.13-next.0", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index c67c3a3ded..d85fb95fce 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,66 @@ # @backstage/plugin-catalog-backend-module-github +## 0.10.2-next.0 + +### Patch Changes + +- d421b16: This change introduces single user versions of the user group resolution code in the multi org provider that will not page through all membership when updating a single user. +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-catalog-backend@3.0.1-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..adbf7af817 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.2-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index ef52007f50..09eeba3cc0 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -36,6 +36,7 @@ import { createRemoveEntitiesOperation, createReplaceEntitiesOperation, createGraphqlClient, + getOrganizationTeamsForUser, } from './github'; import { Octokit } from '@octokit/core'; import { throttling } from '@octokit/plugin-throttling'; @@ -53,6 +54,79 @@ describe('github', () => { const graphql = graphqlOctokit.defaults({}); + describe('getOrganizationTeamsForUser', () => { + const org = 'my-org'; + const userLogin = 'testuser'; + + it('returns teams for a user', async () => { + server.use( + graphqlMsw.query('teams', () => + HttpResponse.json({ + data: { + organization: { + teams: { + pageInfo: { hasNextPage: false, endCursor: null }, + nodes: [ + { + slug: 'team1', + combinedSlug: 'my-org/team1', + name: 'Team 1', + description: 'desc', + avatarUrl: '', + editTeamUrl: '', + parentTeam: null, + }, + ], + }, + }, + }, + }), + ), + ); + + const mockTransformer = jest.fn().mockImplementation(async team => ({ + kind: 'Group', + metadata: { name: team.slug }, + })); + + const { teams } = await getOrganizationTeamsForUser( + graphql as any, + org, + userLogin, + mockTransformer as any, + ); + expect(Array.isArray(teams)).toBe(true); + expect(teams[0]).toEqual({ kind: 'Group', metadata: { name: 'team1' } }); + expect(mockTransformer).toHaveBeenCalled(); + }); + + it('returns an empty array if no teams found', async () => { + server.use( + graphqlMsw.query('teams', () => + HttpResponse.json({ + data: { + organization: { + teams: { + pageInfo: { hasNextPage: false, endCursor: null }, + nodes: [], + }, + }, + }, + }), + ), + ); + const mockTransformer = jest.fn().mockResolvedValue(undefined); + const { teams } = await getOrganizationTeamsForUser( + graphql as any, + org, + userLogin, + mockTransformer as any, + ); + expect(Array.isArray(teams)).toBe(true); + expect(teams.length).toBe(0); + }); + }); + describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { const input: QueryResponse = { diff --git a/plugins/catalog-backend-module-github/src/lib/github.ts b/plugins/catalog-backend-module-github/src/lib/github.ts index 6d29782bad..5d51dd35cd 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.ts @@ -346,6 +346,59 @@ export async function getOrganizationTeamsFromUsers( return { teams }; } +export async function getOrganizationTeamsForUser( + client: typeof graphql, + org: string, + userLogin: string, + teamTransformer: TeamTransformer, +): Promise<{ teams: Entity[] }> { + const query = ` + query teams($org: String!, $cursor: String, $userLogins: [String!] = "") { + organization(login: $org) { + teams(first: 100, after: $cursor, userLogins: $userLogins) { + pageInfo { + hasNextPage + endCursor + } + nodes { + slug + combinedSlug + name + description + avatarUrl + editTeamUrl + parentTeam { + slug + } + } + } + } +}`; + + const materialisedTeams = async ( + item: GithubTeamResponse, + ctx: TransformerContext, + ): Promise => { + const team: GithubTeam = { + ...item, + members: [{ login: userLogin }], + }; + + return await teamTransformer(team, ctx); + }; + + const teams = await queryWithPaging( + client, + query, + org, + r => r.organization?.teams, + materialisedTeams, + { org, userLogins: [userLogin] }, + ); + + return { teams }; +} + export async function getOrganizationsFromUser( client: typeof graphql, user: string, diff --git a/plugins/catalog-backend-module-github/src/lib/index.ts b/plugins/catalog-backend-module-github/src/lib/index.ts index 14f78fdeee..f5da0f1c2b 100644 --- a/plugins/catalog-backend-module-github/src/lib/index.ts +++ b/plugins/catalog-backend-module-github/src/lib/index.ts @@ -30,5 +30,9 @@ export { defaultOrganizationTeamTransformer, type TransformerContext, } from './defaultTransformers'; -export { assignGroupsToUsers, buildOrgHierarchy } from './org'; +export { + assignGroupsToUser, + assignGroupsToUsers, + buildOrgHierarchy, +} from './org'; export { parseGithubOrgUrl } from './util'; diff --git a/plugins/catalog-backend-module-github/src/lib/org.test.ts b/plugins/catalog-backend-module-github/src/lib/org.test.ts index 1cdc55a4da..a2e379adc7 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.test.ts @@ -15,7 +15,12 @@ */ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; -import { assignGroupsToUsers, buildMemberOf, buildOrgHierarchy } from './org'; +import { + assignGroupsToUsers, + assignGroupsToUser, + buildMemberOf, + buildOrgHierarchy, +} from './org'; function u(name: string, memberOf: string[] = []): UserEntity { return { @@ -115,6 +120,42 @@ describe('assignGroupsToUsers', () => { }); }); +describe('assignGroupsToUser', () => { + it('should assign the correct groups to a user', () => { + const user: UserEntity = u('u1'); + const groups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'g1' }, + spec: { type: 'team', children: [], members: ['default/u1'] }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'g2' }, + spec: { type: 'team', children: [], members: ['u2'] }, + }, + ]; + assignGroupsToUser(user, groups); + expect(user.spec.memberOf).toEqual(['g1']); + }); + + it('should not assign any groups if user is not a member', () => { + const user: UserEntity = u('u3'); + const groups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'g1' }, + spec: { type: 'team', children: [], members: ['u1'] }, + }, + ]; + assignGroupsToUser(user, groups); + expect(user.spec.memberOf).toEqual([]); + }); +}); + describe('buildMemberOf', () => { it('fills indirect member of groups', () => { const a = g('a', undefined, []); diff --git a/plugins/catalog-backend-module-github/src/lib/org.ts b/plugins/catalog-backend-module-github/src/lib/org.ts index 4336f2d49c..3a0a30e340 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.ts @@ -91,6 +91,29 @@ export function assignGroupsToUsers( } } +// Assign all relevant groups to a single user if the user is a member of each group. +export function assignGroupsToUser(user: UserEntity, groups: GroupEntity[]) { + const userRef = stringifyEntityRef(user); + for (const group of groups) { + const groupKey = + group.metadata.namespace && group.metadata.namespace !== DEFAULT_NAMESPACE + ? `${group.metadata.namespace}/${group.metadata.name}` + : group.metadata.name; + const memberRefs = + group.spec.members?.map(m => + stringifyEntityRef(parseEntityRef(m, { defaultKind: 'user' })), + ) || []; + if (memberRefs.includes(userRef)) { + if (!user.spec.memberOf) { + user.spec.memberOf = []; + } + if (!user.spec.memberOf.includes(groupKey)) { + user.spec.memberOf.push(groupKey); + } + } + } +} + // Ensure that users have their transitive group memberships. Requires that // the groups were previously processed with buildOrgHierarchy() export function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) { diff --git a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts index 2186b11f50..1aa1af46d7 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts @@ -2306,23 +2306,7 @@ describe('GithubMultiOrgEntityProvider', () => { organization: { teams: { pageInfo: { hasNextPage: false }, - nodes: [ - { - slug: 'team', - combinedSlug: 'orgA/team', - name: 'TeamA', - description: 'The one and only team', - avatarUrl: 'http://example.com/team.jpeg', - editTeamUrl: 'https://example.com', - parentTeam: { - slug: 'parent', - }, - members: { - pageInfo: { hasNextPage: false }, - nodes: [], - }, - }, - ], + nodes: [], }, }, }) diff --git a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts index 62b997d7e2..a1c6a17209 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts @@ -60,6 +60,7 @@ import { defaultOrganizationTeamTransformer, defaultUserTransformer, getOrganizationTeams, + assignGroupsToUser, getOrganizationUsers, GithubTeam, TeamTransformer, @@ -73,6 +74,7 @@ import { import { getOrganizationsFromUser, getOrganizationTeam, + getOrganizationTeamsForUser, getOrganizationTeamsFromUsers, } from '../lib/github'; import { splitTeamSlug } from '../lib/util'; @@ -556,15 +558,15 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { headers: orgHeaders, }); - const { teams } = await getOrganizationTeamsFromUsers( + const { teams } = await getOrganizationTeamsForUser( orgClient, userOrg, - [login], + login, this.defaultMultiOrgTeamTransformer.bind(this), ); if (isUserEntity(user) && areGroupEntities(teams)) { - assignGroupsToUsers([user], teams); + assignGroupsToUser(user, teams); } } } @@ -799,15 +801,15 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { headers: orgHeaders, }); - const { teams } = await getOrganizationTeamsFromUsers( + const { teams } = await getOrganizationTeamsForUser( orgClient, userOrg, - [login], + login, this.defaultMultiOrgTeamTransformer.bind(this), ); if (areGroupEntities(teams)) { - assignGroupsToUsers([user], teams); + assignGroupsToUser(user, teams); } } diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index fa25b06614..427da4a408 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.2-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 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..e9c816c4a6 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.12-next.0", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 5725caf17a..5cae7ddcba 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..2000a19792 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.2-next.0", "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..4d1ac222c6 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.7.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-catalog-backend@3.0.1-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.1 + +## 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..5212ee811c 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.3-next.0", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-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..f4c1e746db 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.11.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..ef2d266a79 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.8-next.0", "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..cb8ed569ef 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.0.1-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 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..16722c3ed4 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.13-next.0", "description": "A module that subscribes to catalog related events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index b844e52e5b..318585b52e 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.7.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..849272cfb9 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.3-next.0", "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..73b5896da0 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..00b390c6ed 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.13-next.0", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index db9f89b5d3..42a880806b 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 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..336dc6aaaa 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.13-next.0", "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..cd264b413d 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..896c29efcc 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.11-next.0", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 519f0542d0..a4966abfe0 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.9 + - @backstage/plugin-permission-common@0.9.1 + +## 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..11053d46c9 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.3-next.0", "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..379dd4049d 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,107 @@ # @backstage/plugin-catalog-backend +## 3.0.1-next.0 + +### Patch Changes + +- 3a7dad9: Updated `better-sqlite3` to v12 +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.0-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + +## 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 7e68c4bea9..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?: | { @@ -218,19 +218,5 @@ export interface Config { * housing catalog-info files. */ processingInterval?: HumanDuration | false; - - /** - * Defines if the UrlReaderProcessor should always call the search method of the - * different UrlReaders. - * - * If set to false, the UrlReaderProcessor will use the legacy behavior that tries to - * parse a Git URL and calls search if there's wildcard patterns and readUrl otherwise. - * - * If set to true, the UrlReaderProcessor always call the search method and lets each UrlReader - * determine if it's a search pattern or not. - * - * This flag is temporary and will be enabled by default in future releases. - */ - useUrlReadersSearch?: boolean; }; } diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index aac1b0779c..665d2b0d52 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.1-next.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", @@ -99,14 +99,13 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/repo-tools": "workspace:^", - "@backstage/test-utils": "workspace:^", "@types/core-js": "^2.5.4", "@types/express": "^4.17.6", "@types/git-url-parse": "^9.0.0", "@types/glob": "^8.0.0", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", - "better-sqlite3": "^11.0.0", + "better-sqlite3": "^12.0.0", "luxon": "^3.0.0", "msw": "^1.0.0", "supertest": "^7.0.0", diff --git a/plugins/catalog-backend/report.api.md b/plugins/catalog-backend/report.api.md index 9bb94b2dd5..6e5ca956bc 100644 --- a/plugins/catalog-backend/report.api.md +++ b/plugins/catalog-backend/report.api.md @@ -135,11 +135,7 @@ export function transformLegacyPolicyToProcessor( // @public (undocumented) export class UrlReaderProcessor implements CatalogProcessor { - constructor(options: { - reader: UrlReaderService; - logger: LoggerService; - config?: Config; - }); + constructor(options: { reader: UrlReaderService; logger: LoggerService }); // (undocumented) getProcessorName(): string; // (undocumented) 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/processors/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/processors/UrlReaderProcessor.test.ts index 2d7268eb33..0b17ecb19f 100644 --- a/plugins/catalog-backend/src/processors/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/processors/UrlReaderProcessor.test.ts @@ -30,8 +30,6 @@ import { import { defaultEntityDataParser } from '../util/parse'; import { UrlReaderProcessor } from './UrlReaderProcessor'; import { UrlReaders } from '@backstage/backend-defaults/urlReader'; -import { UrlReaderService } from '@backstage/backend-plugin-api'; -import { mockApis } from '@backstage/test-utils'; describe('UrlReaderProcessor', () => { const mockApiOrigin = 'http://localhost'; @@ -191,11 +189,11 @@ describe('UrlReaderProcessor', () => { expect(generated.location).toBe(spec); expect(generated.error.name).toBe('NotFoundError'); expect(generated.error.message).toBe( - `Unable to read url, NotFoundError: could not read ${mockApiOrigin}/component-notfound.yaml, 404 Not Found`, + `Unable to read url, no matching files found for ${mockApiOrigin}/component-notfound.yaml`, ); }); - it('uses search when there are globs', async () => { + it("uses reader' search method", async () => { const logger = mockServices.logger.mock(); const reader = mockServices.urlReader.mock({ @@ -206,38 +204,6 @@ describe('UrlReaderProcessor', () => { const emit = jest.fn(); - await processor.readLocation( - { type: 'url', target: 'https://github.com/a/b/blob/x/**/b.yaml' }, - false, - emit, - defaultEntityDataParser, - mockCache, - ); - - expect(reader.search).toHaveBeenCalledTimes(1); - }); - - it('uses search when catalog.useUrlReadersSearch flag is set to true', async () => { - const logger = mockServices.logger.mock(); - - const reader: jest.Mocked = { - readUrl: jest.fn(), - readTree: jest.fn(), - search: jest.fn().mockImplementation(async () => []), - }; - - const config = mockApis.config({ - data: { - catalog: { - useUrlReadersSearch: true, - }, - }, - }); - - const processor = new UrlReaderProcessor({ reader, logger, config }); - - const emit = jest.fn(); - await processor.readLocation( { type: 'url', target: 'https://github.com/a/b/blob/x/b.yaml' }, false, diff --git a/plugins/catalog-backend/src/processors/UrlReaderProcessor.ts b/plugins/catalog-backend/src/processors/UrlReaderProcessor.ts index bc383512be..4440a81bae 100644 --- a/plugins/catalog-backend/src/processors/UrlReaderProcessor.ts +++ b/plugins/catalog-backend/src/processors/UrlReaderProcessor.ts @@ -18,7 +18,6 @@ import { Entity } from '@backstage/catalog-model'; import { assertError } from '@backstage/errors'; import limiterFactory, { Limit } from 'p-limit'; import { LocationSpec } from '@backstage/plugin-catalog-common'; -import parseGitUrl from 'git-url-parse'; import { CatalogProcessor, CatalogProcessorCache, @@ -29,7 +28,6 @@ import { processingResult, } from '@backstage/plugin-catalog-node'; import { LoggerService, UrlReaderService } from '@backstage/backend-plugin-api'; -import { Config } from '@backstage/config'; const CACHE_KEY = 'v1'; @@ -48,25 +46,14 @@ export class UrlReaderProcessor implements CatalogProcessor { // This limiter is used for only consuming a limited number of read streams // concurrently. #limiter: Limit; - #useUrlReadersSearch: boolean; constructor( private readonly options: { reader: UrlReaderService; logger: LoggerService; - config?: Config; }, ) { this.#limiter = limiterFactory(5); - - this.#useUrlReadersSearch = - this.options.config?.getOptionalBoolean('catalog.useUrlReadersSearch') || - false; - if (!this.#useUrlReadersSearch) { - this.options.logger.warn( - 'UrlReaderProcessor uses the legacy readUrl/search behavior which will be removed in a future release. Set catalog.useUrlReadersSearch to true to adopt the new behavior.', - ); - } } getProcessorName() { @@ -149,35 +136,13 @@ export class UrlReaderProcessor implements CatalogProcessor { location: string, etag?: string, ): Promise<{ response: { data: Buffer; url: string }[]; etag?: string }> { - // New behavior: always use the search method - if (this.#useUrlReadersSearch) { - const response = await this.options.reader.search(location, { etag }); + const response = await this.options.reader.search(location, { etag }); - const output = response.files.map(async file => ({ - url: file.url, - data: await this.#limiter(file.content), - })); + const output = response.files.map(async file => ({ + url: file.url, + data: await this.#limiter(file.content), + })); - return { response: await Promise.all(output), etag: response.etag }; - } - - // Old behavior: Does it contain globs? I.e. does it contain asterisks or question marks - // (no curly braces for now) - - const { filepath } = parseGitUrl(location); - if (filepath?.match(/[*?]/)) { - const response = await this.options.reader.search(location, { etag }); - const output = response.files.map(async file => ({ - url: file.url, - data: await this.#limiter(file.content), - })); - return { response: await Promise.all(output), etag: response.etag }; - } - - const data = await this.options.reader.readUrl(location, { etag }); - return { - response: [{ url: location, data: await data.buffer() }], - etag: data.etag, - }; + return { response: await Promise.all(output), etag: response.etag }; } } diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index c9d75298c8..93a6a96eb0 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -356,7 +356,7 @@ export class CatalogBuilder { return [ new FileReaderProcessor(), - new UrlReaderProcessor({ reader, logger, config }), + new UrlReaderProcessor({ reader, logger }), new AnnotateLocationEntityProcessor({ integrations }), ]; } @@ -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..ef9af0c8ff 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-catalog-graph +## 0.4.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/types@1.2.1 + +## 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..e9ba663f6f 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.1", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-graph/report-alpha.api.md b/plugins/catalog-graph/report-alpha.api.md index cf5835e35c..230edde3da 100644 --- a/plugins/catalog-graph/report-alpha.api.md +++ b/plugins/catalog-graph/report-alpha.api.md @@ -16,6 +16,35 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { TranslationRef } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +export const catalogGraphTranslationRef: TranslationRef< + 'catalog-graph', + { + readonly 'catalogGraphCard.title': 'Relations'; + readonly 'catalogGraphCard.deepLinkTitle': 'View graph'; + readonly 'catalogGraphPage.title': 'Catalog Graph'; + readonly 'catalogGraphPage.filterToggleButtonTitle': 'Filters'; + readonly 'catalogGraphPage.supportButtonDescription': 'Start tracking your component in by adding it to the software catalog.'; + readonly 'catalogGraphPage.simplifiedSwitchLabel': 'Simplified'; + readonly 'catalogGraphPage.mergeRelationsSwitchLabel': 'Merge relations'; + readonly 'catalogGraphPage.zoomOutDescription': 'Use pinch & zoom to move around the diagram. Click to change active node, shift click to navigate to entity.'; + readonly 'catalogGraphPage.curveFilter.title': 'Curve'; + readonly 'catalogGraphPage.curveFilter.curveStepBefore': 'Step Before'; + readonly 'catalogGraphPage.curveFilter.curveMonotoneX': 'Monotone X'; + readonly 'catalogGraphPage.directionFilter.title': 'Direction'; + readonly 'catalogGraphPage.directionFilter.leftToRight': 'Left to right'; + readonly 'catalogGraphPage.directionFilter.rightToLeft': 'Right to left'; + readonly 'catalogGraphPage.directionFilter.topToBottom': 'Top to bottom'; + readonly 'catalogGraphPage.directionFilter.bottomToTop': 'Bottom to top'; + readonly 'catalogGraphPage.maxDepthFilter.title': 'Max depth'; + readonly 'catalogGraphPage.maxDepthFilter.inputPlaceholder': '∞ Infinite'; + readonly 'catalogGraphPage.maxDepthFilter.clearButtonAriaLabel': 'clear max depth'; + readonly 'catalogGraphPage.selectedKindsFilter.title': 'Kinds'; + readonly 'catalogGraphPage.selectedRelationsFilter.title': 'Relations'; + } +>; // @public (undocumented) const _default: FrontendPlugin< diff --git a/plugins/catalog-graph/src/alpha.tsx b/plugins/catalog-graph/src/alpha.tsx index aa1f6a05cf..6ee16be1c4 100644 --- a/plugins/catalog-graph/src/alpha.tsx +++ b/plugins/catalog-graph/src/alpha.tsx @@ -96,3 +96,5 @@ export default createFrontendPlugin({ }, extensions: [CatalogGraphPage, CatalogGraphEntityCard], }); + +export { catalogGraphTranslationRef } from './translation'; diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx index e09d57bd31..ed8069a8f4 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx @@ -34,6 +34,7 @@ import userEvent from '@testing-library/user-event'; import { catalogGraphRouteRef } from '../../routes'; import { CatalogGraphCard } from './CatalogGraphCard'; import Button from '@material-ui/core/Button'; +import { translationApiRef } from '@backstage/core-plugin-api/alpha'; describe('', () => { let entity: Entity; @@ -52,7 +53,10 @@ describe('', () => { namespace: 'd', }, }; - apis = TestApiRegistry.from([catalogApiRef, catalog]); + apis = TestApiRegistry.from( + [catalogApiRef, catalog], + [translationApiRef, mockApis.translation()], + ); wrapper = ( @@ -213,7 +217,12 @@ describe('', () => { const analyticsApi = mockApis.analytics(); await renderInTestApp( - + {wrapper} , { diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx index a75993a1bc..733f209990 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx @@ -38,6 +38,8 @@ import { EntityRelationsGraph, EntityRelationsGraphProps, } from '../EntityRelationsGraph'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { catalogGraphTranslationRef } from '../../translation'; /** @public */ export type CatalogGraphCardClassKey = 'card' | 'graph'; @@ -66,6 +68,7 @@ export const CatalogGraphCard = ( action?: ReactNode; }, ) => { + const { t } = useTranslationRef(catalogGraphTranslationRef); const { variant = 'gridItem', relationPairs = ALL_RELATION_PAIRS, @@ -81,7 +84,7 @@ export const CatalogGraphCard = ( action, rootEntityNames, onNodeClick, - title = 'Relations', + title = t('catalogGraphCard.title'), zoom = 'enable-on-click', } = props; @@ -133,7 +136,7 @@ export const CatalogGraphCard = ( variant={variant} noPadding deepLink={{ - title: 'View graph', + title: t('catalogGraphCard.deepLinkTitle'), link: catalogGraphUrl, }} > diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx index cf3e628a98..69cb04bf3a 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx @@ -50,6 +50,8 @@ import { SelectedKindsFilter } from './SelectedKindsFilter'; import { SelectedRelationsFilter } from './SelectedRelationsFilter'; import { SwitchFilter } from './SwitchFilter'; import { useCatalogGraphPage } from './useCatalogGraphPage'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { catalogGraphTranslationRef } from '../../translation'; /** @public */ export type CatalogGraphPageClassKey = @@ -136,7 +138,7 @@ export const CatalogGraphPage = ( initialState, entityFilter, } = props; - + const { t } = useTranslationRef(catalogGraphTranslationRef); const navigate = useNavigate(); const classes = useStyles(); const catalogEntityRoute = useRouteRef(entityRouteRef); @@ -192,7 +194,7 @@ export const CatalogGraphPage = ( return (
humanizeEntityRef(e)).join(', ')} /> @@ -203,13 +205,12 @@ export const CatalogGraphPage = ( selected={showFilters} onChange={() => toggleShowFilters()} > - Filters + {t('catalogGraphPage.filterToggleButtonTitle')} } > - Start tracking your component in by adding it to the software - catalog. + {t('catalogGraphPage.supportButtonDescription')} @@ -230,12 +231,12 @@ export const CatalogGraphPage = ( )} @@ -247,9 +248,8 @@ export const CatalogGraphPage = ( display="block" className={classes.legend} > - Use pinch & zoom to move - around the diagram. Click to change active node, shift click to - navigate to entity. + {' '} + {t('catalogGraphPage.zoomOutDescription')} ', () => { - test('should display current curve label', () => { + test('should display current curve label', async () => { const onChange = jest.fn(); - render(); + await renderInTestApp( + , + ); expect(screen.getByText('Monotone X')).toBeInTheDocument(); }); test('should select an alternative curve factory', async () => { const onChange = jest.fn(); - render(); + await renderInTestApp( + , + ); expect(screen.getByText('Step Before')).toBeInTheDocument(); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.tsx index 411c144b05..0e6a941b1a 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.tsx @@ -16,12 +16,10 @@ import { Select, SelectedItems } from '@backstage/core-components'; import Box from '@material-ui/core/Box'; import { useCallback } from 'react'; +import { catalogGraphTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; type Curve = 'curveStepBefore' | 'curveMonotoneX'; -const CURVE_DISPLAY_NAMES: Record = { - curveMonotoneX: 'Monotone X', - curveStepBefore: 'Step Before', -}; export type Props = { value: Curve; @@ -31,6 +29,12 @@ export type Props = { const curves: Array = ['curveMonotoneX', 'curveStepBefore']; export const CurveFilter = ({ value, onChange }: Props) => { + const { t } = useTranslationRef(catalogGraphTranslationRef); + const CURVE_DISPLAY_NAMES: Record = { + curveMonotoneX: t('catalogGraphPage.curveFilter.curveMonotoneX'), + curveStepBefore: t('catalogGraphPage.curveFilter.curveStepBefore'), + }; + const handleChange = useCallback( (v: SelectedItems) => onChange(v as Curve), [onChange], @@ -39,7 +43,7 @@ export const CurveFilter = ({ value, onChange }: Props) => { return ( ({ label: DIRECTION_DISPLAY_NAMES[v], diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx index ef3df7eb53..2e4d5d44a3 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx @@ -14,20 +14,21 @@ * limitations under the License. */ -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import user from '@testing-library/user-event'; import { MaxDepthFilter } from './MaxDepthFilter'; +import { renderInTestApp } from '@backstage/test-utils'; describe('', () => { - test('should display current value', () => { - render( {}} />); + test('should display current value', async () => { + await renderInTestApp( {}} />); expect(screen.getByLabelText('maxp')).toBeInTheDocument(); expect(screen.getByLabelText('maxp')).toHaveValue(5); }); - test('should display infinite if non finite', () => { - render( + test('should display infinite if non finite', async () => { + await renderInTestApp( {}} />, ); @@ -37,7 +38,7 @@ describe('', () => { test('should clear max depth', async () => { const onChange = jest.fn(); - render(); + await renderInTestApp(); expect(onChange).not.toHaveBeenCalled(); await user.click(screen.getByLabelText('clear max depth')); @@ -46,7 +47,7 @@ describe('', () => { test('should set max depth to undefined if below one', async () => { const onChange = jest.fn(); - render(); + await renderInTestApp(); await user.clear(screen.getByLabelText('maxp')); await user.type(screen.getByLabelText('maxp'), '0'); @@ -56,7 +57,7 @@ describe('', () => { test('should select direction', async () => { let value = 5; - render( + await renderInTestApp( { diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx index 33742ad72e..cdd27b9adb 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { useTranslationRef } from '@backstage/frontend-plugin-api'; import Box from '@material-ui/core/Box'; import FormControl from '@material-ui/core/FormControl'; import IconButton from '@material-ui/core/IconButton'; @@ -22,6 +23,7 @@ import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import ClearIcon from '@material-ui/icons/Clear'; import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; +import { catalogGraphTranslationRef } from '../../translation'; export type Props = { value: number; @@ -45,6 +47,7 @@ export const MaxDepthFilter = ({ value, onChange }: Props) => { const classes = useStyles(); const onChangeRef = useRef(onChange); const [currentValue, setCurrentValue] = useState(value); + const { t } = useTranslationRef(catalogGraphTranslationRef); // Keep a fresh reference to the latest callback useEffect(() => { @@ -75,16 +78,20 @@ export const MaxDepthFilter = ({ value, onChange }: Props) => { return ( - Max Depth + + {t('catalogGraphPage.maxDepthFilter.title')} + diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx index 929b22755d..4349d7005a 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx @@ -15,13 +15,18 @@ */ import { ApiProvider } from '@backstage/core-app-api'; -import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; +import { AlertApi, alertApiRef, errorApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; -import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils'; +import { + mockApis, + renderWithEffects, + TestApiRegistry, +} from '@backstage/test-utils'; import { waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { SelectedKindsFilter } from './SelectedKindsFilter'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; +import { translationApiRef } from '@backstage/core-plugin-api/alpha'; const catalogApi = catalogApiMock.mock({ getEntityFacets: jest.fn().mockResolvedValue({ @@ -38,6 +43,8 @@ const catalogApi = catalogApiMock.mock({ const apis = TestApiRegistry.from( [catalogApiRef, catalogApi], [alertApiRef, {} as AlertApi], + [translationApiRef, mockApis.translation()], + [errorApiRef, { post: jest.fn() }], ); describe('', () => { diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx index 4970c4527a..d9a5ef9833 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx @@ -27,6 +27,8 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { useCallback, useEffect, useMemo } from 'react'; import useAsync from 'react-use/esm/useAsync'; +import { catalogGraphTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; /** @public */ export type SelectedKindsFilterClassKey = 'formControl'; @@ -49,6 +51,7 @@ export const SelectedKindsFilter = ({ value, onChange }: Props) => { const classes = useStyles(); const alertApi = useApi(alertApiRef); const catalogApi = useApi(catalogApiRef); + const { t } = useTranslationRef(catalogGraphTranslationRef); const { error, value: kinds } = useAsync(async () => { return await catalogApi @@ -91,13 +94,15 @@ export const SelectedKindsFilter = ({ value, onChange }: Props) => { return ( - Kinds + + {t('catalogGraphPage.selectedKindsFilter.title')} + kinds[normalizedKinds.indexOf(k)] ?? k} diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx index 41df29d072..057842bcdc 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx @@ -19,14 +19,15 @@ import { RELATION_HAS_MEMBER, RELATION_OWNED_BY, } from '@backstage/catalog-model'; -import { render, waitFor, screen } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ALL_RELATION_PAIRS } from '../EntityRelationsGraph'; import { SelectedRelationsFilter } from './SelectedRelationsFilter'; +import { renderInTestApp } from '@backstage/test-utils'; describe('', () => { - test('should render current value', () => { - render( + test('should render current value', async () => { + await renderInTestApp( ', () => { test('should select value', async () => { const onChange = jest.fn(); - render( + await renderInTestApp( ', () => { test('should return undefined if all values are selected', async () => { const onChange = jest.fn(); - render( + await renderInTestApp( p).filter( @@ -92,7 +93,7 @@ describe('', () => { test('should return all values when cleared', async () => { const onChange = jest.fn(); - render( + await renderInTestApp( { const classes = useStyles(); const relations = useMemo(() => relationPairs.flat(), [relationPairs]); + const { t } = useTranslationRef(catalogGraphTranslationRef); const handleChange = useCallback( (_: unknown, v: string[]) => { @@ -65,13 +68,15 @@ export const SelectedRelationsFilter = ({ return ( - Relations + + {t('catalogGraphPage.selectedRelationsFilter.title')} + ; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'page:catalog-import': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index 17260acc14..6f96bfbed1 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -16,7 +16,6 @@ import { configApiRef, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; @@ -53,8 +52,8 @@ const catalogImportPage = PageBlueprint.make({ }); const catalogImportApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogImportApiRef, deps: { discoveryApi: discoveryApiRef, @@ -81,7 +80,6 @@ const catalogImportApi = ApiBlueprint.make({ configApi, }), }), - }, }); /** @alpha */ diff --git a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx index 5a6cad055c..2100d3da81 100644 --- a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx +++ b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx @@ -130,7 +130,7 @@ export const StepInitAnalyzeUrl = (props: StepInitAnalyzeUrlProps) => { } } } catch (e: any) { - setError(e?.data?.error?.message ?? e.message); + setError(e?.body?.error?.message ?? e.message); setSubmitted(false); } }, diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 648648167d..85cec59713 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-catalog-node +## 1.18.0-next.0 + +### Minor Changes + +- 3f4da39: Added the analyze-location endpoint to the CatalogService + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + +## 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..d83c44d1c9 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.18.0-next.0", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-node/report-testUtils.api.md b/plugins/catalog-node/report-testUtils.api.md index 3098888fcb..3fa7057a99 100644 --- a/plugins/catalog-node/report-testUtils.api.md +++ b/plugins/catalog-node/report-testUtils.api.md @@ -5,6 +5,8 @@ ```ts import { AddLocationRequest } from '@backstage/catalog-client'; import { AddLocationResponse } from '@backstage/catalog-client'; +import { AnalyzeLocationRequest } from '@backstage/plugin-catalog-common'; +import { AnalyzeLocationResponse } from '@backstage/plugin-catalog-common'; import { CatalogApi } from '@backstage/catalog-client'; import { CatalogRequestOptions } from '@backstage/catalog-client'; import { CatalogService } from '@backstage/plugin-catalog-node'; @@ -35,6 +37,11 @@ export interface CatalogServiceMock extends CatalogService, CatalogApi { options?: CatalogServiceRequestOptions | CatalogRequestOptions, ): Promise; // (undocumented) + analyzeLocation( + location: AnalyzeLocationRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) getEntities( request?: GetEntitiesRequest, options?: CatalogServiceRequestOptions | CatalogRequestOptions, diff --git a/plugins/catalog-node/report.api.md b/plugins/catalog-node/report.api.md index 807bcaa8d5..debafad5c4 100644 --- a/plugins/catalog-node/report.api.md +++ b/plugins/catalog-node/report.api.md @@ -125,6 +125,11 @@ export interface CatalogService { options: CatalogServiceRequestOptions, ): Promise; // (undocumented) + analyzeLocation( + location: AnalyzeLocationRequest, + options: CatalogServiceRequestOptions, + ): Promise; + // (undocumented) getEntities( request: GetEntitiesRequest | undefined, options: CatalogServiceRequestOptions, diff --git a/plugins/catalog-node/src/catalogService.ts b/plugins/catalog-node/src/catalogService.ts index 51bb1d92e5..9478c6b48a 100644 --- a/plugins/catalog-node/src/catalogService.ts +++ b/plugins/catalog-node/src/catalogService.ts @@ -42,6 +42,10 @@ import { ValidateEntityResponse, } from '@backstage/catalog-client'; import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { + AnalyzeLocationRequest, + AnalyzeLocationResponse, +} from '@backstage/plugin-catalog-common'; /** * @public @@ -132,6 +136,11 @@ export interface CatalogService { locationRef: string, options: CatalogServiceRequestOptions, ): Promise; + + analyzeLocation( + location: AnalyzeLocationRequest, + options: CatalogServiceRequestOptions, + ): Promise; } class DefaultCatalogService implements CatalogService { @@ -301,6 +310,16 @@ class DefaultCatalogService implements CatalogService { ); } + async analyzeLocation( + location: AnalyzeLocationRequest, + options: CatalogServiceRequestOptions, + ): Promise { + return this.#catalogApi.analyzeLocation( + location, + await this.#getOptions(options), + ); + } + async #getOptions( options: CatalogServiceRequestOptions, ): Promise { diff --git a/plugins/catalog-node/src/testUtils/catalogServiceMock.ts b/plugins/catalog-node/src/testUtils/catalogServiceMock.ts index ec469fc927..20e04e12b4 100644 --- a/plugins/catalog-node/src/testUtils/catalogServiceMock.ts +++ b/plugins/catalog-node/src/testUtils/catalogServiceMock.ts @@ -102,5 +102,6 @@ export namespace catalogServiceMock { removeLocationById: jest.fn(), getLocationByEntity: jest.fn(), validateEntity: jest.fn(), + analyzeLocation: jest.fn(), })); } diff --git a/plugins/catalog-node/src/testUtils/types.ts b/plugins/catalog-node/src/testUtils/types.ts index 6e6331a630..96380e9434 100644 --- a/plugins/catalog-node/src/testUtils/types.ts +++ b/plugins/catalog-node/src/testUtils/types.ts @@ -34,6 +34,10 @@ import { ValidateEntityResponse, } from '@backstage/catalog-client'; import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { + AnalyzeLocationRequest, + AnalyzeLocationResponse, +} from '@backstage/plugin-catalog-common'; import { CatalogService, CatalogServiceRequestOptions, @@ -126,4 +130,9 @@ export interface CatalogServiceMock extends CatalogService, CatalogApi { locationRef: string, options?: CatalogServiceRequestOptions | CatalogRequestOptions, ): Promise; + + analyzeLocation( + location: AnalyzeLocationRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; } diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 8ed8a2059b..0354f44a3c 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,99 @@ # @backstage/plugin-catalog-react +## 1.20.0-next.1 + +### Minor Changes + +- 3f4da39: Added the `analyzeLocation` method to `catalogApiMock` + +### Patch Changes + +- defc243: hide pagination `queryparams` if pagination mode is set to none +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/frontend-test-utils@0.3.5-next.1 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-permission-react@0.4.36 + +## 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..13576d707e 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.20.0-next.1", "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-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 560e2ba987..56af7e9a73 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -346,7 +346,11 @@ export const EntityListProvider = ( ignoreQueryPrefix: true, }); const newParams = qs.stringify( - { ...oldParams, filters: queryParams, cursor, offset, limit }, + { + ...oldParams, + filters: queryParams, + ...(paginationMode === 'none' ? {} : { cursor, limit, offset }), + }, { addQueryPrefix: true, arrayFormat: 'repeat' }, ); const newUrl = `${window.location.pathname}${newParams}`; diff --git a/plugins/catalog-react/src/testUtils/catalogApiMock.ts b/plugins/catalog-react/src/testUtils/catalogApiMock.ts index 08520e2a9b..42c6b1004f 100644 --- a/plugins/catalog-react/src/testUtils/catalogApiMock.ts +++ b/plugins/catalog-react/src/testUtils/catalogApiMock.ts @@ -101,5 +101,6 @@ export namespace catalogApiMock { removeLocationById: jest.fn(), getLocationByEntity: jest.fn(), validateEntity: jest.fn(), + analyzeLocation: jest.fn(), })); } 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..b02ed0dcd1 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.20-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + +## 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..bf5936d8f9 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.1", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog-unprocessed-entities/report-alpha.api.md b/plugins/catalog-unprocessed-entities/report-alpha.api.md index 8b53bcb8ae..fa64ed329a 100644 --- a/plugins/catalog-unprocessed-entities/report-alpha.api.md +++ b/plugins/catalog-unprocessed-entities/report-alpha.api.md @@ -5,7 +5,9 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -30,9 +32,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'nav-item:catalog-unprocessed-entities': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx index 34a40b23d7..cfe81eccc8 100644 --- a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx +++ b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -37,8 +36,8 @@ import { rootRouteRef } from '../routes'; /** @alpha */ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogUnprocessedEntitiesApiRef, deps: { discoveryApi: discoveryApiRef, @@ -47,7 +46,6 @@ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new CatalogUnprocessedEntitiesClient(discoveryApi, fetchApi), }), - }, }); /** @alpha */ diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 0b74c17faa..a130b8e3fe 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,122 @@ # @backstage/plugin-catalog +## 1.31.2-next.1 + +### Patch Changes + +- c0ea01b: Fix card scrolling behaviour +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-search-react@1.9.3-next.0 + - @backstage/plugin-techdocs-react@1.3.2-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-techdocs-common@0.1.1 + +## 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..07bbca4d32 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.1", "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..cfbbc5388e 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -6,6 +6,7 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; @@ -13,6 +14,7 @@ import { EntityCardType } from '@backstage/plugin-catalog-react/alpha'; import { EntityContentLayoutProps } from '@backstage/plugin-catalog-react/alpha'; import { EntityContextMenuItemParams } from '@backstage/plugin-catalog-react/alpha'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; @@ -146,9 +148,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:catalog/entity-presentation': ExtensionDefinition<{ kind: 'api'; @@ -161,9 +167,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:catalog/starred-entities': ExtensionDefinition<{ kind: 'api'; @@ -176,9 +186,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'catalog-filter:catalog/kind': ExtensionDefinition<{ config: { @@ -1012,9 +1026,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 +1111,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/DefaultEntityContentLayout.tsx b/plugins/catalog/src/alpha/DefaultEntityContentLayout.tsx index 21276f424a..3188b98437 100644 --- a/plugins/catalog/src/alpha/DefaultEntityContentLayout.tsx +++ b/plugins/catalog/src/alpha/DefaultEntityContentLayout.tsx @@ -41,7 +41,7 @@ const useStyles = makeStyles< flexFlow: 'column nowrap', gap: theme.spacing(3), }, - contentArea: { + mainContent: { display: 'flex', flexFlow: 'column', gap: theme.spacing(3), @@ -51,9 +51,13 @@ const useStyles = makeStyles< infoArea: { display: 'flex', flexFlow: 'column nowrap', - alignItems: 'stretch', + alignItems: 'flex-start', gap: theme.spacing(3), minWidth: 0, + '& > *': { + flexShrink: 0, + flexGrow: 0, + }, }, summaryArea: { minWidth: 0, @@ -65,10 +69,17 @@ const useStyles = makeStyles< marginLeft: theme.spacing(3), }, }, + contentArea: { + display: 'flex', + flexFlow: 'column', + gap: theme.spacing(3), + alignItems: 'stretch', + minWidth: 0, + }, [theme.breakpoints.up('md')]: { root: { display: 'grid', - gap: 0, + gap: theme.spacing(3), gridTemplateAreas: ({ summaryCards }) => ` "${summaryCards ? 'summary' : 'content'} info" "content info" @@ -76,11 +87,8 @@ const useStyles = makeStyles< gridTemplateColumns: ({ infoCards }) => (infoCards ? '2fr 1fr' : '1fr'), alignItems: 'start', }, - infoArea: { - gridArea: 'info', - position: 'sticky', - top: theme.spacing(3), - marginLeft: theme.spacing(3), + mainContent: { + display: 'contents', }, contentArea: { gridArea: 'content', @@ -89,6 +97,25 @@ const useStyles = makeStyles< gridArea: 'summary', marginBottom: theme.spacing(3), }, + infoArea: { + gridArea: 'info', + position: 'sticky', + top: theme.spacing(3), + // this is a little unfortunate, but it's required to make the info cards scrollable + // in a fixed container of the full height when it's stuck. + // 100% doesn't work as that's the height of the entire layout, which is what powers the card scrolling. + maxHeight: '100vh', + overflowY: 'auto', + alignSelf: 'start', + alignItems: 'stretch', + // Hide the scrollbar for the inner info cards + // kind of an accessibility nightmare, but we see. + scrollbarWidth: 'none', + msOverflowStyle: 'none', + '&::-webkit-scrollbar': { + display: 'none', + }, + }, }, })); @@ -144,20 +171,22 @@ export function DefaultEntityContentLayout(props: EntityContentLayoutProps) { {infoCards.map(card => card.element)}
) : null} - {summaryCards.length > 0 ? ( -
- - {summaryCards.map(card => ( -
{card.element}
- ))} -
-
- ) : null} - {contentCards.length > 0 ? ( -
- {contentCards.map(card => card.element)} -
- ) : null} +
+ {summaryCards.length > 0 ? ( +
+ + {summaryCards.map(card => ( +
{card.element}
+ ))} +
+
+ ) : null} + {contentCards.length > 0 ? ( +
+ {contentCards.map(card => card.element)} +
+ ) : null} +
); diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx index d0f80c3aec..6bfa0a124b 100644 --- a/plugins/catalog/src/alpha/apis.tsx +++ b/plugins/catalog/src/alpha/apis.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, discoveryApiRef, fetchApiRef, storageApiRef, @@ -33,8 +32,8 @@ import { } from '../apis'; export const catalogApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: catalogApiRef, deps: { discoveryApi: discoveryApiRef, @@ -43,31 +42,28 @@ export const catalogApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new CatalogClient({ discoveryApi, fetchApi }), }), - }, }); export const catalogStarredEntitiesApi = ApiBlueprint.make({ name: 'starred-entities', - params: { - factory: createApiFactory({ + params: define => + define({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), }), - }, }); export const entityPresentationApi = ApiBlueprint.make({ name: 'entity-presentation', - params: { - factory: createApiFactory({ + params: define => + define({ api: entityPresentationApiRef, deps: { catalogApiImp: catalogApiRef }, factory: ({ catalogApiImp }) => DefaultEntityPresentationApi.create({ catalogApi: catalogApiImp }), }), - }, }); export default [catalogApi, catalogStarredEntitiesApi, entityPresentationApi]; 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 ( ; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'nav-item:devtools': ExtensionDefinition<{ kind: 'nav-item'; diff --git a/plugins/devtools/src/alpha/plugin.tsx b/plugins/devtools/src/alpha/plugin.tsx index 52caaf4786..d2f09521dd 100644 --- a/plugins/devtools/src/alpha/plugin.tsx +++ b/plugins/devtools/src/alpha/plugin.tsx @@ -15,7 +15,6 @@ */ import { - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -34,8 +33,8 @@ import { rootRouteRef } from '../routes'; /** @alpha */ export const devToolsApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: devToolsApiRef, deps: { discoveryApi: discoveryApiRef, @@ -44,7 +43,6 @@ export const devToolsApi = ApiBlueprint.make({ factory: ({ discoveryApi, fetchApi }) => new DevToolsClient({ discoveryApi, fetchApi }), }), - }, }); /** @alpha */ diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index dab40a9419..05cc56b910 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + +## 0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 5fa5d43d6a..4c3131b4d3 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.4.12", + "version": "0.4.14-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 76b66181ad..38de0391fd 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.2.21 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 04eb908a12..5fa78cee94 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.2.21", + "version": "0.2.23-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 45d8d2230b..776e9b3158 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.2.21 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index b44fba658e..76bc9bc7af 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.2.21", + "version": "0.2.23-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md index 32b0e55e7a..6f74c057cd 100644 --- a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-events-backend-module-bitbucket-server +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-server/package.json b/plugins/events-backend-module-bitbucket-server/package.json index 7045b0fa3e..c0c1fd613a 100644 --- a/plugins/events-backend-module-bitbucket-server/package.json +++ b/plugins/events-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-server", - "version": "0.1.2", + "version": "0.1.4-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index d6a78b0c4d..57a90d352b 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.2.21 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index b613407c59..d9e61ad1f7 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.2.21", + "version": "0.2.23-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index ced999124e..f6ae7e3fce 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-events-backend-module-github +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/integration@1.17.1 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.4.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-events-node@0.4.13-next.0 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.17.1-next.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + ## 0.4.1 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 8506063943..4a522338f3 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.4.1", + "version": "0.4.3-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 2b5daa381b..d0fb34ddab 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.3.2 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index b02ece2332..d44d7873f9 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.3.2", + "version": "0.3.4-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-google-pubsub/CHANGELOG.md b/plugins/events-backend-module-google-pubsub/CHANGELOG.md index 24ab6b3969..d9321fcf7c 100644 --- a/plugins/events-backend-module-google-pubsub/CHANGELOG.md +++ b/plugins/events-backend-module-google-pubsub/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-events-backend-module-google-pubsub +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/events-backend-module-google-pubsub/package.json b/plugins/events-backend-module-google-pubsub/package.json index 36a7468173..43ee0df11a 100644 --- a/plugins/events-backend-module-google-pubsub/package.json +++ b/plugins/events-backend-module-google-pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-google-pubsub", - "version": "0.1.1", + "version": "0.1.3-next.0", "description": "The google-pubsub backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-module-kafka/CHANGELOG.md b/plugins/events-backend-module-kafka/CHANGELOG.md index a259c90614..2cc2ebee81 100644 --- a/plugins/events-backend-module-kafka/CHANGELOG.md +++ b/plugins/events-backend-module-kafka/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-events-backend-module-kafka +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/events-backend-module-kafka/package.json b/plugins/events-backend-module-kafka/package.json index 9e92ef1345..c2b5c0d10f 100644 --- a/plugins/events-backend-module-kafka/package.json +++ b/plugins/events-backend-module-kafka/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-kafka", - "version": "0.1.0", + "version": "0.1.2-next.0", "description": "The kafka backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index e9a355c610..7a5f9596d8 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.14-next.0 + +## 0.1.46 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.13 + +## 0.1.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.1.45 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 6cdb45110f..3a63eaaff9 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.45", + "version": "0.1.47-next.0", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index e0a28c935a..5ac34b864d 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3 + - @backstage/backend-openapi-utils@0.5.5 + - @backstage/backend-plugin-api@1.4.1 + - @backstage/plugin-events-node@0.4.13 + +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.3-next.0 + - @backstage/backend-plugin-api@1.4.1-next.0 + - @backstage/backend-openapi-utils@0.5.5-next.0 + - @backstage/plugin-events-node@0.4.13-next.0 + ## 0.5.3 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 79cee20cda..5ab50ffe27 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.5.3", + "version": "0.5.5-next.0", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 235b37dcc2..b35a20ad64 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-events-node +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 92c7bb3b37..cb82c8e79e 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.4.12", + "version": "0.4.14-next.0", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 13b66a91d0..7dafaa0d1c 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @internal/plugin-todo-list-backend +## 1.0.42-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + +## 1.0.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 1.0.40 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 508b70af1f..85aa64ec63 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.40", + "version": "1.0.42-next.0", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 09a053b1ac..72a97d5d14 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @internal/plugin-todo-list-common +## 1.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1 + +## 1.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.9.1-next.0 + ## 1.0.25 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 6c1b783755..3858b463dc 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.25", + "version": "1.0.26", "backstage": { "role": "common-library", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 10d2ab94ba..dd15458823 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,37 @@ # @internal/plugin-todo-list +## 1.0.42-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4 + - @backstage/core-plugin-api@1.10.9 + +## 1.0.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.1 + - @backstage/core-plugin-api@1.10.9-next.0 + +## 1.0.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.4-next.0 + - @backstage/core-plugin-api@1.10.8 + ## 1.0.40 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index f42ccd267d..b893715607 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.40", + "version": "1.0.42-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/gateway-backend/CHANGELOG.md b/plugins/gateway-backend/CHANGELOG.md index a75b886136..4ac9c38af1 100644 --- a/plugins/gateway-backend/CHANGELOG.md +++ b/plugins/gateway-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-gateway-backend +## 1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 1.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1 + +## 1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.1-next.0 + ## 1.0.2 ### Patch Changes diff --git a/plugins/gateway-backend/package.json b/plugins/gateway-backend/package.json index f33b9041e7..01240b51aa 100644 --- a/plugins/gateway-backend/package.json +++ b/plugins/gateway-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gateway-backend", - "version": "1.0.2", + "version": "1.0.4-next.0", "backstage": { "role": "backend-plugin", "pluginId": "gateway", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 829ec3eea2..1cd70dc92b 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-home-react +## 0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + +## 0.1.28 + +### 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.28-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.28-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.27 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 47466e61e8..9e3b697123 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.27", + "version": "0.1.29-next.0", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index c28c6528a0..d75acb9382 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-home +## 0.8.11-next.1 + +### Patch Changes + +- f16d380: Add the missing Visits API to the alpha plugin, fixing a crash due to the API not being installed. +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-home-react@0.1.29-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/core-app-api@1.18.0 + - @backstage/core-plugin-api@1.10.9 + +## 0.8.11-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.10 + +### Patch Changes + +- d52d67f: Added a New Frontend System App Root Element for the `` 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..1494dc1bfd 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.1", "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..010918b029 100644 --- a/plugins/home/report-alpha.api.md +++ b/plugins/home/report-alpha.api.md @@ -3,8 +3,11 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -19,6 +22,40 @@ const _default: FrontendPlugin< }, {}, { + 'api:home/visits': ExtensionDefinition<{ + kind: 'api'; + name: 'visits'; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; + }>; + '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..d093f353a2 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -21,8 +21,14 @@ import { PageBlueprint, createFrontendPlugin, createRouteRef, + AppRootElementBlueprint, + identityApiRef, + storageApiRef, + ApiBlueprint, } from '@backstage/frontend-plugin-api'; import { compatWrapper } from '@backstage/core-compat-api'; +import { VisitListener } from './components/'; +import { visitsApiRef, VisitsStorageApi } from './api'; const rootRouteRef = createRouteRef(); @@ -63,13 +69,34 @@ const homePage = PageBlueprint.makeWithOverrides({ }, }); +const visitListenerAppRootElement = AppRootElementBlueprint.make({ + name: 'visit-listener', + params: { + element: , + }, +}); + +const visitsApi = ApiBlueprint.make({ + name: 'visits', + params: define => + define({ + api: visitsApiRef, + deps: { + storageApi: storageApiRef, + identityApi: identityApiRef, + }, + factory: ({ storageApi, identityApi }) => + VisitsStorageApi.create({ storageApi, identityApi }), + }), +}); + /** * @alpha */ export default createFrontendPlugin({ pluginId: 'home', info: { packageJson: () => import('../package.json') }, - extensions: [homePage], + extensions: [homePage, visitsApi, visitListenerAppRootElement], routes: { root: rootRouteRef, }, diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 656321d450..07be8ce1ab 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-kubernetes-backend +## 0.19.9-next.0 + +### Patch Changes + +- 00ebaeb: Remove usage of the deprecated `loggerToWinstonLogger` from `@backstage/backend-common`. +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-kubernetes-node@0.3.3-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.17 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.6 + - @backstage/plugin-permission-common@0.9.1 + +## 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..35631a2d1e 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.9-next.0", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index e176285a49..fb3efc0b3c 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -42,10 +42,7 @@ import { LoggerService, PermissionsService, } from '@backstage/backend-plugin-api'; -import { - createLegacyAuthAdapters, - loggerToWinstonLogger, -} from '@backstage/backend-common'; +import { createLegacyAuthAdapters } from '@backstage/backend-common'; export const APPLICATION_JSON: string = 'application/json'; @@ -153,8 +150,13 @@ export class KubernetesProxy { if (!middleware) { const logger = this.logger.child({ cluster: originalCluster.name }); middleware = createProxyMiddleware({ - // TODO: Add 'log' to LoggerService - logProvider: () => loggerToWinstonLogger(logger), + logProvider: () => ({ + log: logger.info.bind(logger), + debug: logger.debug.bind(logger), + info: logger.info.bind(logger), + warn: logger.warn.bind(logger), + error: logger.error.bind(logger), + }), ws: true, secure: !originalCluster.skipTLSVerify, changeOrigin: true, diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index fef1236d13..d25adab013 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-kubernetes-common@0.9.6 + - @backstage/plugin-kubernetes-react@0.5.10-next.0 + - @backstage/plugin-permission-react@0.4.36 + +## 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..f0d69ee7fd 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.1", "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..552646545b 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-kubernetes-node +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 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..f49590e79d 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.3-next.0", "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..f9f9761e9f 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-kubernetes-react +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.6 + +## 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..54a92a9b4f 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.10-next.0", "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..aa5a519f79 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-kubernetes +## 0.12.10-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-kubernetes-common@0.9.6 + - @backstage/plugin-kubernetes-react@0.5.10-next.0 + - @backstage/plugin-permission-react@0.4.36 + +## 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..f1e4a9196b 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.1", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes/report-alpha.api.md b/plugins/kubernetes/report-alpha.api.md index e6cc199ae8..37bb084bd7 100644 --- a/plugins/kubernetes/report-alpha.api.md +++ b/plugins/kubernetes/report-alpha.api.md @@ -5,10 +5,12 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } 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'; @@ -33,9 +35,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/auth-providers': ExtensionDefinition<{ kind: 'api'; @@ -48,9 +54,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/cluster-link-formatter': ExtensionDefinition<{ kind: 'api'; @@ -63,9 +73,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'api:kubernetes/proxy': ExtensionDefinition<{ kind: 'api'; @@ -78,9 +92,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'entity-content:kubernetes/kubernetes': ExtensionDefinition<{ kind: 'entity-content'; diff --git a/plugins/kubernetes/src/alpha/apis.tsx b/plugins/kubernetes/src/alpha/apis.tsx index 082a2da6c7..c57e9a1482 100644 --- a/plugins/kubernetes/src/alpha/apis.tsx +++ b/plugins/kubernetes/src/alpha/apis.tsx @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/frontend-plugin-api'; @@ -41,8 +40,8 @@ import { } from '@backstage/core-plugin-api'; export const kubernetesApiExtension = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesApiRef, deps: { discoveryApi: discoveryApiRef, @@ -56,13 +55,12 @@ export const kubernetesApiExtension = ApiBlueprint.make({ kubernetesAuthProvidersApi, }), }), - }, }); export const kubernetesProxyApi = ApiBlueprint.make({ name: 'proxy', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesProxyApiRef, deps: { kubernetesApi: kubernetesApiRef, @@ -72,13 +70,12 @@ export const kubernetesProxyApi = ApiBlueprint.make({ kubernetesApi, }), }), - }, }); export const kubernetesAuthProvidersApi = ApiBlueprint.make({ name: 'auth-providers', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesAuthProvidersApiRef, deps: { gitlabAuthApi: gitlabAuthApiRef, @@ -109,13 +106,12 @@ export const kubernetesAuthProvidersApi = ApiBlueprint.make({ }); }, }), - }, }); export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({ name: 'cluster-link-formatter', - params: { - factory: createApiFactory({ + params: define => + define({ api: kubernetesClusterLinkFormatterApiRef, deps: { googleAuthApi: googleAuthApiRef }, factory: deps => { @@ -126,5 +122,4 @@ export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({ }); }, }), - }, }); diff --git a/plugins/mcp-actions-backend/CHANGELOG.md b/plugins/mcp-actions-backend/CHANGELOG.md index a00d07bda8..563f2bdd0b 100644 --- a/plugins/mcp-actions-backend/CHANGELOG.md +++ b/plugins/mcp-actions-backend/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-mcp-actions-backend +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 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..ea3463b509 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.2-next.0", "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..39e0d0e3d0 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-notifications-node@0.2.18-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/integration-aws-node@0.1.17 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.10 + +## 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..cc75d06224 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.12-next.0", "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..277e77a95e 100644 --- a/plugins/notifications-backend-module-slack/CHANGELOG.md +++ b/plugins/notifications-backend-module-slack/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-notifications-backend-module-slack +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-notifications-node@0.2.18-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.10 + +## 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..dcc2a1adcc 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.4-next.0", "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..f6150320c6 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,72 @@ # @backstage/plugin-notifications-backend +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/plugin-notifications-node@0.2.18-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-signals-node@0.1.23-next.0 + +## 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..112d671cc8 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.9-next.0", "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..bd37c413d2 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-notifications-node +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-signals-node@0.1.23-next.0 + +## 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..13a0889913 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.18-next.0", "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..a4e0a188c2 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-notifications +## 0.5.8-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.10 + - @backstage/plugin-signals-react@0.0.15 + +## 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..a39b403f38 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.1", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications/report-alpha.api.md b/plugins/notifications/report-alpha.api.md index 734dd0a201..b512d97ce3 100644 --- a/plugins/notifications/report-alpha.api.md +++ b/plugins/notifications/report-alpha.api.md @@ -5,7 +5,9 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } 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'; @@ -29,9 +31,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory, + ) => ExtensionBlueprintParams; }>; 'page:notifications': ExtensionDefinition<{ kind: 'page'; diff --git a/plugins/notifications/src/alpha.tsx b/plugins/notifications/src/alpha.tsx index 4424659593..68d0ccab8d 100644 --- a/plugins/notifications/src/alpha.tsx +++ b/plugins/notifications/src/alpha.tsx @@ -17,7 +17,6 @@ import { ApiBlueprint, PageBlueprint, - createApiFactory, createFrontendPlugin, discoveryApiRef, fetchApiRef, @@ -41,14 +40,13 @@ const page = PageBlueprint.make({ }); const api = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: notificationsApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, factory: ({ discoveryApi, fetchApi }) => new NotificationsClient({ discoveryApi, fetchApi }), }), - }, }); /** @alpha */ diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index f570e99ecb..45d776604c 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-org-react +## 0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + +## 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..6c8fa528a4 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.1", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 79481c4512..727d6d4254 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/plugin-org +## 0.6.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/plugin-catalog-common@1.1.5 + +## 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..f0773597d4 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.1", "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..4f6bd6c191 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-permission-common@0.9.1 + +## 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..446a8a4e59 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.11-next.0", "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..2bdcc96b2c 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-permission-backend +## 0.7.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.1 + +## 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..6ad3640147 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.3-next.0", "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/plugins/permission-common/src/types/deprecated.ts b/plugins/permission-common/src/types/deprecated.ts new file mode 100644 index 0000000000..e2a4e404e4 --- /dev/null +++ b/plugins/permission-common/src/types/deprecated.ts @@ -0,0 +1,30 @@ +/* + * 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 { EvaluatePermissionRequest, EvaluatePermissionResponse } from './api'; +import { AuthorizeRequestOptions } from './permission'; + +/** + * 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..3a855bf38f 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-permission-node +## 0.10.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.1 + +## 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..af101a7500 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.3-next.0", "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..0f8fd69a22 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-proxy-backend +## 0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-proxy-node@0.1.7-next.0 + - @backstage/types@1.2.1 + +## 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..4447c20d53 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.5-next.0", "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..167c8742fb 100644 --- a/plugins/proxy-node/CHANGELOG.md +++ b/plugins/proxy-node/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-proxy-node +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + +## 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..92e0ffde7d 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.7-next.0", "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..cf763e0270 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..6df38b028b 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.12-next.0", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index d301f3c62c..4d4595c79c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + +## 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..cb73f625dd 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.12-next.0", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index e65f866b2a..813609a611 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..a02789f992 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.12-next.0", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 24566d2810..1ddf48c9f9 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.12-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..be7e72dcb8 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.13-next.0", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 41fdbd8e44..9555bc61cc 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..6e05ed6dc9 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.12-next.0", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-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..f0f706737b 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + +## 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..3e27ad15a9 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.14-next.0", "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..3ff86ac0ea 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..2d07b01102 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.12-next.0", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index d795bf2275..d73f996de7 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..258bf7e200 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.12-next.0", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index e4cf277e46..70864c66b7 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..978a40e3f1 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.12-next.0", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 88220d2042..8de1be5979 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,101 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.8.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + +## 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..f0de334761 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.2-next.0", "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..1fea614b4d 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.9.4-next.0 + +### Patch Changes + +- df2bfab: The `description` property in `publish:gitlab:merge-request` has been made optional again to comply with the GitLab API. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + +## 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..93f4bb747d 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.4-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-gitlab/report.api.md b/plugins/scaffolder-backend-module-gitlab/report.api.md index 07e3ed87b4..1c4ce80995 100644 --- a/plugins/scaffolder-backend-module-gitlab/report.api.md +++ b/plugins/scaffolder-backend-module-gitlab/report.api.md @@ -218,8 +218,8 @@ export const createPublishGitlabMergeRequestAction: (options: { { repoUrl: string; title: string; - description: string; branchName: string; + description?: string | undefined; targetBranchName?: string | undefined; sourcePath?: string | undefined; targetPath?: string | undefined; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index a9ee80a30f..66c72b4c46 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -157,7 +157,10 @@ Accepts the format \`gitlab.com?repo=project_name&owner=group_name\` where \ \`project_name\` is the repository name and \`group_name\` is a group or username`), title: z => z.string().describe('The name for the merge request'), description: z => - z.string().describe('The description of the merge request'), + z + .string() + .optional() + .describe('The description of the merge request'), branchName: z => z.string().describe('The source branch name of the merge request'), targetBranchName: z => diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 0cc9672729..4a9578db3a 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/plugin-notifications-node@0.2.18-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-notifications-common@0.0.10 + +## 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..77c41d9758 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.13-next.0", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 6f8631be4a..a82fc034f1 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + +## 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..bd2e21fa46 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.12-next.0", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 59a7223fb7..f0f4f3361c 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + +## 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..35d746e1ed 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.12-next.0", "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..ea384447a2 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.3.2-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/types@1.2.1 + +## 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..e0aee18d22 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.13-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/.eslintrc.js b/plugins/scaffolder-backend/.eslintrc.js index 953af54f90..3c5416068f 100644 --- a/plugins/scaffolder-backend/.eslintrc.js +++ b/plugins/scaffolder-backend/.eslintrc.js @@ -5,13 +5,13 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { name: 'path', importNames: ['resolve'], message: - 'Do not use path.resolve, use `resolveSafeChildPath` from `@backstage/backend-common` instead as it prevents security issues', + 'Do not use path.resolve, use `resolveSafeChildPath` from `@backstage/backend-plugin-api` instead as it prevents security issues', }, ], restrictedSrcSyntax: [ { message: - 'Do not use path.resolve, use `resolveSafeChildPath` from `@backstage/backend-common` instead as it prevents security issues', + 'Do not use path.resolve, use `resolveSafeChildPath` from `@backstage/backend-plugin-api` instead as it prevents security issues', selector: 'MemberExpression[object.name="path"][property.name="resolve"]', }, ], diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 2169f7d96c..e9c944ff8f 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,165 @@ # @backstage/plugin-scaffolder-backend +## 2.2.0-next.0 + +### Minor Changes + +- c08cbc4: Move Scaffolder API to OpenAPI +- 812485c: Add step info to scaffolder action context to access the step id and name. + +### Patch Changes + +- caee2eb: Fixed WinstonLogger throwing when redactions were null or undefined +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/backend-openapi-utils@0.6.0-next.0 + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.4-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.12-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.8.2-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.1 + - @backstage/plugin-permission-common@0.9.1 + +## 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 d3fb0fa81b..c63bf1c8a1 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.2.0-next.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", @@ -54,6 +54,7 @@ "build": "backstage-cli package build", "build:assets": "node scripts/build-nunjucks.js", "clean": "backstage-cli package clean", + "generate": "backstage-repo-tools package schema openapi generate --server --client-package plugins/scaffolder-common", "lint": "backstage-cli package lint", "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack", @@ -61,8 +62,8 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "^0.25.0", "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-openapi-utils": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", @@ -90,7 +91,6 @@ "@types/luxon": "^3.0.0", "concat-stream": "^2.0.0", "express": "^4.17.1", - "express-promise-router": "^4.1.0", "fs-extra": "^11.2.0", "globby": "^11.0.0", "isbinaryfile": "^5.0.0", @@ -120,6 +120,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-scaffolder-node-test-utils": "workspace:^", + "@backstage/repo-tools": "workspace:^", "@types/express": "^4.17.6", "@types/fs-extra": "^11.0.0", "@types/nunjucks": "^3.1.4", 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 1f2a17a384..ada936c6e9 100644 --- a/plugins/scaffolder-backend/report.api.md +++ b/plugins/scaffolder-backend/report.api.md @@ -14,9 +14,9 @@ import { Duration } from 'luxon'; import { EventsService } from '@backstage/plugin-events-node'; import { HumanDuration } from '@backstage/types'; import { JsonObject } from '@backstage/types'; -import { JsonValue } 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'; @@ -28,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'; @@ -38,6 +39,7 @@ import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateFilter } from '@backstage/plugin-scaffolder-node'; import { TemplateGlobal } from '@backstage/plugin-scaffolder-node'; import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node/alpha'; import { UrlReaderService } from '@backstage/backend-plugin-api'; import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; @@ -351,6 +353,7 @@ export class DatabaseTaskStore implements TaskStore { order: 'asc' | 'desc'; field: string; }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number; @@ -442,19 +445,9 @@ export class TaskManager implements TaskContext { // (undocumented) get spec(): TaskSpecV1beta3; // (undocumented) - updateCheckpoint?( - options: - | { - key: string; - status: 'success'; - value: JsonValue; - } - | { - key: string; - status: 'failed'; - reason: string; - }, - ): Promise<void>; + get taskId(): string; + // (undocumented) + updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>; } // @public @deprecated @@ -498,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/ScaffolderPlugin.test.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts index b9cb397ae6..f3b3456e79 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts @@ -737,9 +737,10 @@ describe('scaffolderPlugin', () => { }); // Retry the task by ID - response = await request(server).post( - `/api/scaffolder/v2/tasks/${taskId}/retry`, - ); + response = await request(server) + .post(`/api/scaffolder/v2/tasks/${taskId}/retry`) + .send({}); + expect(response.status).toBe(201); expect(response.body).toMatchObject({ id: taskId }); diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index 9d4494c536..d384443252 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -22,7 +22,11 @@ import { import type { UserEntity } from '@backstage/catalog-model'; import { ScmIntegrations } from '@backstage/integration'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import { TaskSpec, TemplateInfo } from '@backstage/plugin-scaffolder-common'; +import { + ScaffolderTaskStatus, + TaskSpec, + TemplateInfo, +} from '@backstage/plugin-scaffolder-common'; import { createTemplateAction, deserializeDirectoryContents, @@ -54,7 +58,13 @@ interface DryRunInput { } interface DryRunResult { - log: Array<{ body: JsonObject }>; + log: Array<{ + body: { + message: string; + stepId?: string; + status?: ScaffolderTaskStatus; + }; + }>; directoryContents: SerializedFile[]; output: JsonObject; } @@ -106,7 +116,13 @@ export function createDryRunner(options: TemplateTesterCreateOptions) { const contentsPath = path.dirname(basePath); const dryRunId = uuid(); - const log = new Array<{ body: JsonObject }>(); + const log = new Array<{ + body: { + message: string; + stepId?: string; + status?: ScaffolderTaskStatus; + }; + }>(); try { await deserializeDirectoryContents(contentsPath, input.directoryContents); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts index eb0418b5ed..03a85ad971 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts @@ -14,14 +14,19 @@ * limitations under the License. */ -import { DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager } from '@backstage/backend-defaults/database'; import { ConfigReader } from '@backstage/config'; import { DatabaseTaskStore, RawDbTaskEventRow } from './DatabaseTaskStore'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { ConflictError } from '@backstage/errors'; -import { createMockDirectory } from '@backstage/backend-test-utils'; +import { + mockServices, + createMockDirectory, +} 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( @@ -33,7 +38,10 @@ const createStore = async (events?: EventsService) => { }, }, }), - ).forPlugin('scaffolder'); + ).forPlugin('scaffolder', { + logger: mockServices.logger.mock(), + lifecycle: mockServices.lifecycle.mock(), + }); const store = await DatabaseTaskStore.create({ database: manager, events, @@ -231,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..fdcaa8613e 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> { @@ -536,7 +607,7 @@ export class DatabaseTaskStore implements TaskStore { const events = rawEvents.map(event => { try { - const body = JSON.parse(event.body) as JsonObject; + const body = JSON.parse(event.body) as SerializedTaskEvent['body']; return { id: Number(event.id), isTaskRecoverable, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 79a847c46d..8019bd4134 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -361,6 +361,24 @@ describe('NunjucksWorkflowRunner', () => { expect.objectContaining({ backstageToken: token }), ); }); + + it('should pass step info through', async () => { + const task = createMockTaskWithSpec({ + steps: [ + { + id: 'test', + name: 'name', + action: 'jest-validated-action', + input: { foo: 1 }, + }, + ], + }); + + await runner.execute(task); + + expect(fakeActionHandler.mock.calls[0][0].step.id).toEqual('test'); + expect(fakeActionHandler.mock.calls[0][0].step.name).toEqual('name'); + }); }); describe('conditionals', () => { @@ -1447,6 +1465,35 @@ describe('NunjucksWorkflowRunner', () => { fakeActionHandler.mock.calls[0][0].templateInfo.entity.metadata.name, ).toEqual('test-template'); }); + + it('should have step info in action context during dry run', async () => { + const task = createMockTaskWithSpec( + { + templateInfo: { + entityRef: 'dryRun-Entity', + entity: { metadata: { name: 'test-template' } }, + }, + steps: [ + { + id: 'test', + name: 'name', + action: 'jest-validated-action', + input: { foo: 1 }, + }, + ], + }, + { + backstageToken: token, + }, + true, + ); + + await runner.execute(task); + + expect(fakeActionHandler.mock.calls[0][0].isDryRun).toEqual(true); + expect(fakeActionHandler.mock.calls[0][0].step.id).toEqual('test'); + expect(fakeActionHandler.mock.calls[0][0].step.name).toEqual('name'); + }); }); describe('permissions', () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 7802a7ab8d..d069a6bc1c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -60,6 +60,10 @@ import { scaffolderActionRules } from '../../service/rules'; import { createCounterMetric, createHistogramMetric } from '../../util/metrics'; import { BackstageLoggerTransport, WinstonLogger } from './logger'; import { convertFiltersToRecord } from '../../util/templating'; +import { + CheckpointState, + CheckpointContext, +} from '@backstage/plugin-scaffolder-node/alpha'; type NunjucksWorkflowRunnerOptions = { workingDirectory: string; @@ -91,16 +95,6 @@ type TemplateContext = { }; }; -type CheckpointState = - | { - status: 'failed'; - reason: string; - } - | { - status: 'success'; - value: JsonValue; - }; - const isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => { return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3'; }; @@ -384,10 +378,9 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { secrets: task.secrets ?? {}, logger: taskLogger, workspacePath, - async checkpoint<T extends JsonValue | void>(opts: { - key?: string; - fn: () => Promise<T> | T; - }) { + async checkpoint<T extends JsonValue | void>( + opts: CheckpointContext<T>, + ) { const { key: checkpointKey, fn } = opts; const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`; @@ -396,9 +389,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { if (prevTaskState) { const prevState = ( - prevTaskState.state?.checkpoints as { - [key: string]: CheckpointState; - } + prevTaskState.state?.checkpoints as CheckpointState )?.[key]; if (prevState && prevState.status === 'success') { @@ -447,6 +438,10 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { isDryRun: task.isDryRun, signal: task.cancelSignal, getInitiatorCredentials: () => task.getInitiatorCredentials(), + step: { + id: step.id, + name: step.name, + }, }); } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts index dc89100b95..2b13130908 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager } from '@backstage/backend-defaults/database'; import { ConfigReader } from '@backstage/config'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { @@ -36,7 +36,10 @@ async function createStore(): Promise<DatabaseTaskStore> { }, }, }), - ).forPlugin('scaffolder'); + ).forPlugin('scaffolder', { + logger: mockServices.logger.mock(), + lifecycle: mockServices.lifecycle.mock(), + }); return await DatabaseTaskStore.create({ database: manager, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index 86f9f7fcf7..5b4d568144 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -29,33 +29,24 @@ import { TaskBrokerDispatchOptions, TaskCompletionState, TaskContext, + TaskFilters, TaskSecrets, TaskStatus, } from '@backstage/plugin-scaffolder-node'; -import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; import { - JsonObject, - JsonValue, - Observable, - createDeferred, -} from '@backstage/types'; + CheckpointState, + WorkspaceProvider, + UpdateTaskCheckpointOptions, +} from '@backstage/plugin-scaffolder-node/alpha'; +import { JsonObject, Observable, createDeferred } from '@backstage/types'; 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: { - [key: string]: - | { - status: 'failed'; - reason: string; - } - | { - status: 'success'; - value: JsonValue; - }; - }; + checkpoints: CheckpointState; }; /** * TaskManager @@ -105,6 +96,10 @@ export class TaskManager implements TaskContext { private readonly auth?: AuthService, ) {} + get taskId() { + return this.task.taskId; + } + get spec() { return this.task.spec; } @@ -152,20 +147,9 @@ export class TaskManager implements TaskContext { return this.storage.getTaskState?.({ taskId: this.task.taskId }); } - async updateCheckpoint?( - options: - | { - key: string; - status: 'success'; - value: JsonValue; - } - | { - key: string; - status: 'failed'; - reason: string; - }, - ): Promise<void> { + async updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void> { const { key, ...value } = options; + if (this.task.state) { (this.task.state as TaskState).checkpoints[key] = value; } else { @@ -291,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.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts index dd9233a5ee..6fedc4df40 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts @@ -15,7 +15,7 @@ */ import os from 'os'; -import { DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager } from '@backstage/backend-defaults/database'; import { ConfigReader } from '@backstage/config'; import { DatabaseTaskStore } from './DatabaseTaskStore'; import { StorageTaskBroker } from './StorageTaskBroker'; @@ -49,7 +49,10 @@ async function createStore(): Promise<DatabaseTaskStore> { }, }, }), - ).forPlugin('scaffolder'); + ).forPlugin('scaffolder', { + logger: mockServices.logger.mock(), + lifecycle: mockServices.lifecycle.mock(), + }); return await DatabaseTaskStore.create({ database: manager, }); 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/logger.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/logger.test.ts new file mode 100644 index 0000000000..ae83c1d719 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/logger.test.ts @@ -0,0 +1,75 @@ +/* + * 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 { WinstonLogger } from './logger'; +import { MESSAGE } from 'triple-beam'; + +describe('WinstonLogger', () => { + describe('redacter', () => { + describe('add method', () => { + it('should handle null and undefined values in newRedactions without crashing', () => { + const { add, format } = WinstonLogger.redacter(); + + expect(() => { + add([null as any, undefined as any, 'valid-secret']); + }).not.toThrow(); + + const testObj = { + level: 'info', + message: 'This contains valid-secret and should be redacted', + [MESSAGE]: 'This contains valid-secret and should be redacted', + }; + const result = format.transform(testObj); + expect((result as any)?.[MESSAGE]).toBe( + 'This contains *** and should be redacted', + ); + }); + + it('should skip empty and single character redactions', () => { + const { add, format } = WinstonLogger.redacter(); + + add(['', 'x', 'valid-secret-123']); + + // MESSAGE symbol is where Winston stores the formatted message for redaction + const testObj = { + level: 'info', + message: 'This contains valid-secret-123 and should be redacted', + [MESSAGE]: 'This contains valid-secret-123 and should be redacted', + }; + + const result = format.transform(testObj); + expect((result as any)?.[MESSAGE]).toBe( + 'This contains *** and should be redacted', + ); + }); + + it('should trim whitespace from redactions', () => { + const { add, format } = WinstonLogger.redacter(); + + add([' secret-with-spaces \n', ' another-secret\t']); + + const testObj = { + level: 'info', + message: 'This contains secret-with-spaces and another-secret', + [MESSAGE]: 'This contains secret-with-spaces and another-secret', + }; + + const result = format.transform(testObj); + expect((result as any)?.[MESSAGE]).toBe('This contains *** and ***'); + }); + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/logger.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/logger.ts index 38263b73ca..a8e844c827 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/logger.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/logger.ts @@ -132,6 +132,10 @@ export class WinstonLogger implements RootLoggerService { add(newRedactions) { let added = 0; for (const redactionToTrim of newRedactions) { + // Skip null or undefined values + if (redactionToTrim === null || redactionToTrim === undefined) { + continue; + } // Trimming the string ensures that we don't accdentally get extra // newlines or other whitespace interfering with the redaction; this // can happen for example when using string literals in yaml diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/taskRecoveryHelper.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/taskRecoveryHelper.ts index f3b8b321fe..fa75bdb2df 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/taskRecoveryHelper.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/taskRecoveryHelper.ts @@ -28,7 +28,7 @@ export const trimEventsTillLastRecovery = ( if (recoveredEventInd >= 0) { const ind = events.length - recoveredEventInd - 1; const { recoverStrategy } = events[ind].body as { - recoverStrategy: TaskRecoverStrategy; + recoverStrategy?: TaskRecoverStrategy; }; if (recoverStrategy === 'startOver') { return { 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/schema/openapi.yaml b/plugins/scaffolder-backend/src/schema/openapi.yaml new file mode 100644 index 0000000000..b89f54603c --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi.yaml @@ -0,0 +1,887 @@ +openapi: 3.0.3 +info: + title: scaffolder + version: '1' + description: The Backstage backend plugin that helps you create new things + license: + name: Apache-2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + contact: {} +servers: + - url: / +components: + examples: {} + headers: {} + parameters: + createdBy: + name: createdBy + in: query + description: Created by + required: false + allowReserved: true + schema: + type: array + items: + type: string + eventsAfter: + name: after + in: query + description: Offset event ID to stream events after. + required: false + allowReserved: true + schema: + type: integer + kind: + name: kind + in: path + required: true + allowReserved: true + schema: + type: string + limit: + name: limit + in: query + description: Number of records to return in the response. + required: false + allowReserved: true + schema: + type: integer + minimum: 0 + namespace: + name: namespace + in: path + required: true + allowReserved: true + schema: + type: string + name: + name: name + in: path + required: true + allowReserved: true + schema: + type: string + offset: + name: offset + in: query + description: Number of records to skip in the query page. + required: false + allowReserved: true + schema: + type: integer + minimum: 0 + order: + name: order + in: query + description: Order + required: false + allowReserved: true + schema: + type: array + items: + type: string + status: + name: status + in: query + description: Status + required: false + allowReserved: true + schema: + type: array + items: + type: string + taskId: + name: taskId + in: path + required: true + allowReserved: true + schema: + type: string + requestBodies: {} + responses: + ErrorResponse: + description: An error response from the backend. + content: + application/json; charset=utf-8: + schema: + $ref: '#/components/schemas/Error' + schemas: + Action: + type: object + properties: + id: + type: string + description: + type: string + "'examples'": + type: array + items: + $ref: '#/components/schemas/ActionExample' + schema: + type: object + properties: + input: + $ref: '#/components/schemas/JsonObject' + output: + $ref: '#/components/schemas/JsonObject' + required: + - id + description: The response shape for a single action in the `listActions` call to the `scaffolder-backend` + ActionExample: + type: object + properties: + description: + type: string + example: + type: string + required: + - description + - example + description: A single action example + DryRunResult: + type: object + properties: + log: + type: array + items: + type: object + properties: + body: + allOf: + - $ref: '#/components/schemas/JsonObject' + - type: object + properties: + message: + type: string + status: + $ref: '#/components/schemas/TaskStatus' + stepId: + type: string + required: + - message + required: + - body + directoryContents: + type: array + items: + $ref: '#/components/schemas/SerializedFile' + output: + $ref: '#/components/schemas/JsonObject' + required: + - log + - directoryContents + - output + Error: + type: object + properties: + error: + type: object + properties: + name: + type: string + message: + type: string + stack: + type: string + code: + type: string + required: + - name + - message + request: + type: object + properties: + method: + type: string + url: + type: string + required: + - method + - url + response: + type: object + properties: + statusCode: + type: number + required: + - statusCode + required: + - error + - response + additionalProperties: {} + JsonArray: + type: array + items: + $ref: '#/components/schemas/JsonValue' + description: A type representing all allowed JSON array values. + JsonObject: + type: object + properties: {} + description: A type representing all allowed JSON object values. + additionalProperties: {} + JsonPrimitive: + oneOf: + - type: boolean + - type: number + - type: string + - type: object + nullable: true + description: A type representing all allowed JSON primitive values. + JsonValue: + oneOf: + - $ref: '#/components/schemas/JsonObject' + - $ref: '#/components/schemas/JsonArray' + - $ref: '#/components/schemas/JsonPrimitive' + description: A type representing all allowed JSON values. + ListActionsResponse: + type: array + items: + $ref: '#/components/schemas/Action' + description: The response shape for the `listActions` call to the `scaffolder-backend` + ListTasksResponse: + type: object + properties: + tasks: + type: array + items: + $ref: '#/components/schemas/SerializedTask' + totalTasks: + type: number + required: + - tasks + description: The response shape for the `listTasks` call to the `scaffolder-backend` + ListTemplatingExtensionsResponse: + type: object + properties: + filters: + type: object + additionalProperties: + $ref: '#/components/schemas/TemplateFilter' + globals: + type: object + properties: + functions: + type: object + additionalProperties: + $ref: '#/components/schemas/TemplateGlobalFunction' + values: + type: object + additionalProperties: + $ref: '#/components/schemas/TemplateGlobalValue' + required: + - functions + - values + required: + - filters + - globals + description: The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend` + ScaffolderScaffoldOptions: + type: object + properties: + templateRef: + type: string + values: + type: object + additionalProperties: {} + secrets: + type: object + additionalProperties: + type: string + required: + - templateRef + - values + description: The input options to the `scaffold` method of the `ScaffolderClient`. + ScaffolderUsageExample: + type: object + properties: + description: + type: string + example: + type: string + notes: + type: string + required: + - example + description: A single scaffolder usage example + SerializedFile: + type: object + properties: + path: + type: string + content: + type: string + executable: + type: boolean + symlink: + type: boolean + required: + - path + - content + SerializedTaskEvent: + type: object + properties: + id: + type: integer + isTaskRecoverable: + type: boolean + taskId: + type: string + body: + allOf: + - $ref: '#/components/schemas/JsonObject' + - type: object + properties: + message: + type: string + status: + $ref: '#/components/schemas/TaskStatus' + stepId: + type: string + required: + - message + type: + $ref: '#/components/schemas/TaskEventType' + createdAt: + type: string + required: + - id + - taskId + - body + - type + - createdAt + description: SerializedTaskEvent + SerializedTask: + type: object + properties: + id: + type: string + spec: + type: object + status: + $ref: '#/components/schemas/TaskStatus' + createdAt: + type: string + lastHeartbeatAt: + type: string + createdBy: + type: string + secrets: + $ref: '#/components/schemas/TaskSecrets' + state: + $ref: '#/components/schemas/JsonObject' + required: + - id + - spec + - status + - createdAt + description: SerializedTask + TaskEventType: + type: string + description: TaskEventType + enum: + - cancelled + - completion + - log + - recovered + TaskSecrets: + allOf: + - type: object + additionalProperties: + type: string + - type: object + properties: + backstageToken: + type: string + description: TaskSecrets + TaskStatus: + type: string + enum: + - cancelled + - completed + - failed + - open + - processing + - skipped + description: The status of each step of the Task + TemplateGlobalFunction: + type: object + properties: + description: + type: string + schema: + type: object + properties: + arguments: + type: array + items: + $ref: '#/components/schemas/JsonObject' + output: + $ref: '#/components/schemas/JsonObject' + "'examples'": + type: array + items: + $ref: '#/components/schemas/ScaffolderUsageExample' + description: The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend` + TemplateGlobalValue: + type: object + properties: + description: + type: string + value: + type: object + nullable: true + required: + - value + description: The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend` + TemplateFilter: + type: object + properties: + description: + type: string + schema: + type: object + properties: + input: + $ref: '#/components/schemas/JsonObject' + arguments: + type: array + items: + $ref: '#/components/schemas/JsonObject' + output: + $ref: '#/components/schemas/JsonObject' + "'examples'": + type: array + items: + $ref: '#/components/schemas/ScaffolderUsageExample' + description: The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend` + TemplateParameterSchema: + type: object + properties: + title: + type: string + description: + type: string + steps: + type: array + items: + type: object + properties: + title: + type: string + description: + type: string + schema: + type: object + required: + - title + - schema + required: + - title + - steps + description: |- + The shape of each entry of parameters which gets rendered + as a separate step in the wizard input + additionalProperties: {} + ValidationError: + type: object + properties: + path: + type: array + items: + oneOf: + - type: string + - type: integer + property: + type: string + message: + type: string + instance: + type: object + name: + type: string + argument: + oneOf: + - type: boolean + - type: number + - type: object + - type: string + stack: + type: string + required: + - path + - property + - message + - schema + - instance + - name + - argument + - stack + additionalProperties: {} + securitySchemes: + JWT: + type: http + scheme: bearer + bearerFormat: JWT +paths: + /v2/templates/{namespace}/{kind}/{name}/parameter-schema: + get: + operationId: GetTemplateParameterSchema + description: Get template parameter schema. + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/TemplateParameterSchema' + '400': + $ref: '#/components/responses/ErrorResponse' + default: + $ref: '#/components/responses/ErrorResponse' + security: + - {} + - JWT: [] + parameters: + - $ref: '#/components/parameters/namespace' + - $ref: '#/components/parameters/kind' + - $ref: '#/components/parameters/name' + + /v2/actions: + get: + operationId: ListActions + description: Returns a list of all installed actions. + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ListActionsResponse' + security: + - {} + - JWT: [] + parameters: [] + + /v2/tasks: + get: + operationId: ListTasks + description: Returns a list of tasks, filtering by ownership and/or status if given. + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ListTasksResponse' + security: + - {} + - JWT: [] + parameters: + - $ref: '#/components/parameters/createdBy' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/order' + - $ref: '#/components/parameters/status' + post: + operationId: Scaffold + description: |- + Executes the scaffolding of a component, given a template and its + parameter values. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ScaffolderScaffoldOptions' + responses: + '201': + description: Created + content: + application/json: + schema: + type: object + properties: + id: + type: string + required: + - id + '400': + description: Validation errors. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + $ref: '#/components/schemas/ValidationError' + required: + - errors + security: + - {} + - JWT: [] + parameters: [] + + /v2/tasks/{taskId}: + get: + operationId: GetTask + description: Get a task by ID. + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/SerializedTask' + '403': + $ref: '#/components/responses/ErrorResponse' + security: + - {} + - JWT: [] + parameters: + - $ref: '#/components/parameters/taskId' + + /v2/tasks/{taskId}/cancel: + post: + operationId: CancelTask + description: Sends a signal to a task broker to cancel the running task by taskId. + responses: + '200': + description: Ok + content: + application/json: + schema: + type: object + properties: + status: + $ref: '#/components/schemas/TaskStatus' + security: + - {} + - JWT: [] + parameters: + - $ref: '#/components/parameters/taskId' + + /v2/tasks/{taskId}/retry: + post: + operationId: Retry + description: Starts the task again from the point where it failed. + requestBody: + # this should probably be marked as required, but for legacy reasons we're not. + required: false + content: + application/json: + schema: + type: object + properties: + secrets: + type: object + additionalProperties: + type: string + responses: + '201': + description: Ok + content: + application/json: + schema: + type: object + properties: + id: + type: string + required: + - id + security: + - {} + - JWT: [] + parameters: + - $ref: '#/components/parameters/taskId' + + /v2/tasks/{taskId}/events: + get: + operationId: StreamLogsPolling + description: Get events for a task by ID. + responses: + '200': + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SerializedTaskEvent' + '403': + $ref: '#/components/responses/ErrorResponse' + parameters: + - $ref: '#/components/parameters/eventsAfter' + - $ref: '#/components/parameters/taskId' + + /v2/dry-run: + post: + operationId: DryRun + description: Perform a dry-run of a template + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + template: + type: object + values: + $ref: '#/components/schemas/JsonObject' + secrets: + type: object + additionalProperties: + type: string + directoryContents: + type: array + items: + type: object + properties: + path: + type: string + base64Content: + type: string + required: + - template + - values + - directoryContents + responses: + '200': + description: Ok + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/DryRunResult' + - type: object + properties: + steps: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + action: + type: string + required: + - id + - name + - action + additionalProperties: {} + directoryContents: + type: array + items: + type: object + properties: + path: + type: string + executable: + type: boolean + base64Content: + type: string + required: + - path + - base64Content + required: + - steps + '400': + description: Validation errors. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + $ref: '#/components/schemas/ValidationError' + required: + - errors + parameters: [] + + /v2/autocomplete/{provider}/{resource}: + post: + operationId: Autocomplete + description: Perform an autocomplete for the given provider and resource. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + context: + type: object + additionalProperties: + type: string + token: + type: string + required: + - context + - token + responses: + '200': + description: Ok + content: + application/json: + schema: + type: object + properties: + results: + type: array + items: + type: object + properties: + title: + type: string + id: + type: string + required: + - id + required: + - results + '400': + description: Unsupported provider. + content: + application/json: + schema: + type: object + properties: + message: + type: string + name: + type: string + parameters: + - in: path + name: provider + required: true + allowReserved: true + schema: + type: string + - in: path + name: resource + required: true + allowReserved: true + schema: + type: string + + /v2/templating-extensions: + get: + operationId: ListTemplatingExtensions + description: Returns a structure describing the available templating extensions. + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ListTemplatingExtensionsResponse' + security: + - {} + - JWT: [] + parameters: [] diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts new file mode 100644 index 0000000000..c5bd9f0ac2 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts @@ -0,0 +1,163 @@ +/* + * 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. + */ + +// + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Action } from '../models/Action.model'; +import { Autocomplete200Response } from '../models/Autocomplete200Response.model'; +import { Autocomplete400Response } from '../models/Autocomplete400Response.model'; +import { AutocompleteRequest } from '../models/AutocompleteRequest.model'; +import { CancelTask200Response } from '../models/CancelTask200Response.model'; +import { DryRun200Response } from '../models/DryRun200Response.model'; +import { DryRunRequest } from '../models/DryRunRequest.model'; +import { ListTasksResponse } from '../models/ListTasksResponse.model'; +import { ListTemplatingExtensionsResponse } from '../models/ListTemplatingExtensionsResponse.model'; +import { RetryRequest } from '../models/RetryRequest.model'; +import { Scaffold201Response } from '../models/Scaffold201Response.model'; +import { Scaffold400Response } from '../models/Scaffold400Response.model'; +import { ScaffolderScaffoldOptions } from '../models/ScaffolderScaffoldOptions.model'; +import { SerializedTask } from '../models/SerializedTask.model'; +import { SerializedTaskEvent } from '../models/SerializedTaskEvent.model'; +import { TemplateParameterSchema } from '../models/TemplateParameterSchema.model'; + +/** + * @public + */ +export type Autocomplete = { + path: { + provider: string; + resource: string; + }; + body: AutocompleteRequest; + response: Autocomplete200Response | Autocomplete400Response; +}; +/** + * @public + */ +export type CancelTask = { + path: { + taskId: string; + }; + response: CancelTask200Response; +}; +/** + * @public + */ +export type DryRun = { + body: DryRunRequest; + response: DryRun200Response | Scaffold400Response; +}; +/** + * @public + */ +export type GetTask = { + path: { + taskId: string; + }; + response: SerializedTask | Error; +}; +/** + * @public + */ +export type GetTemplateParameterSchema = { + path: { + namespace: string; + kind: string; + name: string; + }; + response: TemplateParameterSchema | Error | Error; +}; +/** + * @public + */ +export type ListActions = { + response: Array<Action>; +}; +/** + * @public + */ +export type ListTasks = { + query: { + createdBy?: Array<string>; + limit?: number; + offset?: number; + order?: Array<string>; + status?: Array<string>; + }; + response: ListTasksResponse; +}; +/** + * @public + */ +export type ListTemplatingExtensions = { + response: ListTemplatingExtensionsResponse; +}; +/** + * @public + */ +export type Retry = { + path: { + taskId: string; + }; + body: RetryRequest; + response: Scaffold201Response; +}; +/** + * @public + */ +export type Scaffold = { + body: ScaffolderScaffoldOptions; + response: Scaffold201Response | Scaffold400Response; +}; +/** + * @public + */ +export type StreamLogsPolling = { + path: { + taskId: string; + }; + query: { + after?: number; + }; + response: Array<SerializedTaskEvent> | Error; +}; + +export type EndpointMap = { + '#post|/v2/autocomplete/{provider}/{resource}': Autocomplete; + + '#post|/v2/tasks/{taskId}/cancel': CancelTask; + + '#post|/v2/dry-run': DryRun; + + '#get|/v2/tasks/{taskId}': GetTask; + + '#get|/v2/templates/{namespace}/{kind}/{name}/parameter-schema': GetTemplateParameterSchema; + + '#get|/v2/actions': ListActions; + + '#get|/v2/tasks': ListTasks; + + '#get|/v2/templating-extensions': ListTemplatingExtensions; + + '#post|/v2/tasks/{taskId}/retry': Retry; + + '#post|/v2/tasks': Scaffold; + + '#get|/v2/tasks/{taskId}/events': StreamLogsPolling; +}; diff --git a/packages/canon/src/components/Tabs/types.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/index.ts similarity index 68% rename from packages/canon/src/components/Tabs/types.ts rename to plugins/scaffolder-backend/src/schema/openapi/generated/apis/index.ts index f3b6342761..8d81cbaf39 100644 --- a/packages/canon/src/components/Tabs/types.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/index.ts @@ -13,13 +13,11 @@ * 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 +// -/** @public */ -export interface TabsRootWithoutOrientation - extends Omit< - React.ComponentPropsWithoutRef<typeof Tabs.Root>, - 'orientation' - > {} +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +export * from './Api.server'; diff --git a/packages/canon/src/components/Tabs/index.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/index.ts similarity index 87% rename from packages/canon/src/components/Tabs/index.ts rename to plugins/scaffolder-backend/src/schema/openapi/generated/index.ts index ba6ca91de7..dec4b8804e 100644 --- a/packages/canon/src/components/Tabs/index.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { Tabs } from './Tabs'; -export type { TabsRootWithoutOrientation } from './types'; +export * from './apis'; +export * from './router'; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Action.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Action.model.ts new file mode 100644 index 0000000000..f9c028f3e3 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Action.model.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ActionExample } from '../models/ActionExample.model'; +import { ActionSchema } from '../models/ActionSchema.model'; + +/** + * The response shape for a single action in the `listActions` call to the `scaffolder-backend` + * @public + */ +export interface Action { + id: string; + description?: string; + examples?: Array<ActionExample>; + schema?: ActionSchema; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionExample.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionExample.model.ts new file mode 100644 index 0000000000..50550e2883 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionExample.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A single action example + * @public + */ +export interface ActionExample { + description: string; + example: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionSchema.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionSchema.model.ts new file mode 100644 index 0000000000..35d2014181 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ActionSchema.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ActionSchema { + /** + * A type representing all allowed JSON object values. + */ + input?: { [key: string]: any }; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200Response.model.ts new file mode 100644 index 0000000000..e3eec0aa20 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Autocomplete200ResponseResultsInner } from '../models/Autocomplete200ResponseResultsInner.model'; + +/** + * @public + */ +export interface Autocomplete200Response { + results: Array<Autocomplete200ResponseResultsInner>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts new file mode 100644 index 0000000000..00ccb41b0f --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete200ResponseResultsInner { + title?: string; + id: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts new file mode 100644 index 0000000000..1456babb96 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete400Response { + message?: string; + name?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/AutocompleteRequest.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/AutocompleteRequest.model.ts new file mode 100644 index 0000000000..769a929918 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/AutocompleteRequest.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface AutocompleteRequest { + context: { [key: string]: string }; + token: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/CancelTask200Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/CancelTask200Response.model.ts new file mode 100644 index 0000000000..f29c509d41 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/CancelTask200Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface CancelTask200Response { + status?: TaskStatus; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200Response.model.ts new file mode 100644 index 0000000000..62e3689d5d --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200Response.model.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRun200ResponseAllOfDirectoryContentsInner } from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +import { DryRun200ResponseAllOfStepsInner } from '../models/DryRun200ResponseAllOfStepsInner.model'; +import { DryRunResultLogInner } from '../models/DryRunResultLogInner.model'; + +/** + * @public + */ +export interface DryRun200Response { + log: Array<DryRunResultLogInner>; + directoryContents: Array<DryRun200ResponseAllOfDirectoryContentsInner>; + /** + * A type representing all allowed JSON object values. + */ + output: { [key: string]: any }; + steps: Array<DryRun200ResponseAllOfStepsInner>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts new file mode 100644 index 0000000000..5b6c2ff9c7 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRun200ResponseAllOfDirectoryContentsInner } from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +import { DryRun200ResponseAllOfStepsInner } from '../models/DryRun200ResponseAllOfStepsInner.model'; + +/** + * @public + */ +export interface DryRun200ResponseAllOf { + steps: Array<DryRun200ResponseAllOfStepsInner>; + directoryContents?: Array<DryRun200ResponseAllOfDirectoryContentsInner>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts new file mode 100644 index 0000000000..2646ca49f9 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRun200ResponseAllOfDirectoryContentsInner { + path: string; + executable?: boolean; + base64Content: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts new file mode 100644 index 0000000000..2a462edefa --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRun200ResponseAllOfStepsInner { + [key: string]: any; + + id: string; + name: string; + action: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequest.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequest.model.ts new file mode 100644 index 0000000000..212b36c26b --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequest.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunRequestDirectoryContentsInner } from '../models/DryRunRequestDirectoryContentsInner.model'; + +/** + * @public + */ +export interface DryRunRequest { + template: any; + /** + * A type representing all allowed JSON object values. + */ + values: { [key: string]: any }; + secrets?: { [key: string]: string }; + directoryContents: Array<DryRunRequestDirectoryContentsInner>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts new file mode 100644 index 0000000000..ddcae4fd9d --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRunRequestDirectoryContentsInner { + path?: string; + base64Content?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResult.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResult.model.ts new file mode 100644 index 0000000000..6e2ad23ef4 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResult.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInner } from '../models/DryRunResultLogInner.model'; +import { SerializedFile } from '../models/SerializedFile.model'; + +/** + * @public + */ +export interface DryRunResult { + log: Array<DryRunResultLogInner>; + directoryContents: Array<SerializedFile>; + /** + * A type representing all allowed JSON object values. + */ + output: { [key: string]: any }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts new file mode 100644 index 0000000000..4c6b786d82 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInnerBody } from '../models/DryRunResultLogInnerBody.model'; + +/** + * @public + */ +export interface DryRunResultLogInner { + body: DryRunResultLogInnerBody; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts new file mode 100644 index 0000000000..e3b19be045 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface DryRunResultLogInnerBody { + message: string; + status?: TaskStatus; + stepId?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts new file mode 100644 index 0000000000..e67240ee54 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface DryRunResultLogInnerBodyAllOf { + message: string; + status?: TaskStatus; + stepId?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorError.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..e0265e95d7 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorError.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorError { + name: string; + message: string; + stack?: string; + code?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..3eb5e15740 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..edbcc32df7 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorResponse { + statusCode: number; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonPrimitive.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonPrimitive.model.ts new file mode 100644 index 0000000000..6aa6394c14 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonPrimitive.model.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A type representing all allowed JSON primitive values. + * @public + */ +export type JsonPrimitive = any | boolean | number | string; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonValue.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonValue.model.ts new file mode 100644 index 0000000000..9fe2ac9de3 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/JsonValue.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { JsonPrimitive } from '../models/JsonPrimitive.model'; + +/** + * A type representing all allowed JSON values. + * @public + */ +export type JsonValue = + | Array<JsonValue> + | JsonPrimitive + | { [key: string]: any }; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTasksResponse.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTasksResponse.model.ts new file mode 100644 index 0000000000..9347c766a9 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTasksResponse.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { SerializedTask } from '../models/SerializedTask.model'; + +/** + * The response shape for the `listTasks` call to the `scaffolder-backend` + * @public + */ +export interface ListTasksResponse { + tasks: Array<SerializedTask>; + totalTasks?: number; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts new file mode 100644 index 0000000000..74b7cd3780 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ListTemplatingExtensionsResponseGlobals } from '../models/ListTemplatingExtensionsResponseGlobals.model'; +import { TemplateFilter } from '../models/TemplateFilter.model'; + +/** + * The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface ListTemplatingExtensionsResponse { + filters: { [key: string]: TemplateFilter }; + globals: ListTemplatingExtensionsResponseGlobals; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts new file mode 100644 index 0000000000..1f022a0675 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TemplateGlobalFunction } from '../models/TemplateGlobalFunction.model'; +import { TemplateGlobalValue } from '../models/TemplateGlobalValue.model'; + +/** + * @public + */ +export interface ListTemplatingExtensionsResponseGlobals { + functions: { [key: string]: TemplateGlobalFunction }; + values: { [key: string]: TemplateGlobalValue }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ModelError.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..958fde7d0b --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ModelError.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +/** + * @public + */ +export interface ModelError { + [key: string]: any; + + error: ErrorError; + request?: ErrorRequest; + response: ErrorResponse; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/RetryRequest.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/RetryRequest.model.ts new file mode 100644 index 0000000000..858fa67566 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/RetryRequest.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface RetryRequest { + secrets?: { [key: string]: string }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold201Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold201Response.model.ts new file mode 100644 index 0000000000..1271642e81 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold201Response.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Scaffold201Response { + id: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold400Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold400Response.model.ts new file mode 100644 index 0000000000..e3cb7eaa45 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Scaffold400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ValidationError } from '../models/ValidationError.model'; + +/** + * @public + */ +export interface Scaffold400Response { + errors: Array<ValidationError>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts new file mode 100644 index 0000000000..93f4ae71c0 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * The input options to the `scaffold` method of the `ScaffolderClient`. + * @public + */ +export interface ScaffolderScaffoldOptions { + templateRef: string; + values: { [key: string]: any }; + secrets?: { [key: string]: string }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts new file mode 100644 index 0000000000..3e0f4ef866 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A single scaffolder usage example + * @public + */ +export interface ScaffolderUsageExample { + description?: string; + example: string; + notes?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedFile.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedFile.model.ts new file mode 100644 index 0000000000..65a3c714a7 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedFile.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface SerializedFile { + path: string; + content: string; + executable?: boolean; + symlink?: boolean; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTask.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTask.model.ts new file mode 100644 index 0000000000..67cbf14279 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTask.model.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskSecrets } from '../models/TaskSecrets.model'; +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * SerializedTask + * @public + */ +export interface SerializedTask { + id: string; + spec: any; + status: TaskStatus; + createdAt: string; + lastHeartbeatAt?: string; + createdBy?: string; + secrets?: TaskSecrets; + /** + * A type representing all allowed JSON object values. + */ + state?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts new file mode 100644 index 0000000000..6e4ddaa296 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInnerBody } from '../models/DryRunResultLogInnerBody.model'; +import { TaskEventType } from '../models/TaskEventType.model'; + +/** + * SerializedTaskEvent + * @public + */ +export interface SerializedTaskEvent { + id: number; + isTaskRecoverable?: boolean; + taskId: string; + body: DryRunResultLogInnerBody; + type: TaskEventType; + createdAt: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskEventType.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskEventType.model.ts new file mode 100644 index 0000000000..d32d77a448 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskEventType.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type TaskEventType = 'cancelled' | 'completion' | 'log' | 'recovered'; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecrets.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecrets.model.ts new file mode 100644 index 0000000000..c78c39c1ec --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecrets.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * TaskSecrets + * @public + */ +export interface TaskSecrets { + backstageToken?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts new file mode 100644 index 0000000000..0b33852cc9 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TaskSecretsAllOf { + backstageToken?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskStatus.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskStatus.model.ts new file mode 100644 index 0000000000..1f209a3656 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TaskStatus.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type TaskStatus = + | 'cancelled' + | 'completed' + | 'failed' + | 'open' + | 'processing' + | 'skipped'; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilter.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilter.model.ts new file mode 100644 index 0000000000..7c631978e6 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilter.model.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ScaffolderUsageExample } from '../models/ScaffolderUsageExample.model'; +import { TemplateFilterSchema } from '../models/TemplateFilterSchema.model'; + +/** + * The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateFilter { + description?: string; + schema?: TemplateFilterSchema; + examples?: Array<ScaffolderUsageExample>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts new file mode 100644 index 0000000000..5a95a58ead --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateFilterSchema { + /** + * A type representing all allowed JSON object values. + */ + input?: { [key: string]: any }; + arguments?: Array<{ [key: string]: any }>; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts new file mode 100644 index 0000000000..ee19ce723b --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ScaffolderUsageExample } from '../models/ScaffolderUsageExample.model'; +import { TemplateGlobalFunctionSchema } from '../models/TemplateGlobalFunctionSchema.model'; + +/** + * The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateGlobalFunction { + description?: string; + schema?: TemplateGlobalFunctionSchema; + examples?: Array<ScaffolderUsageExample>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts new file mode 100644 index 0000000000..b3a39c3b24 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateGlobalFunctionSchema { + arguments?: Array<{ [key: string]: any }>; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts new file mode 100644 index 0000000000..95d177a05a --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateGlobalValue { + description?: string; + value: any | null; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts new file mode 100644 index 0000000000..8638ee8114 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TemplateParameterSchemaStepsInner } from '../models/TemplateParameterSchemaStepsInner.model'; + +/** + * The shape of each entry of parameters which gets rendered as a separate step in the wizard input + * @public + */ +export interface TemplateParameterSchema { + [key: string]: any; + + title: string; + description?: string; + steps: Array<TemplateParameterSchemaStepsInner>; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts new file mode 100644 index 0000000000..2f7892fd41 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateParameterSchemaStepsInner { + title: string; + description?: string; + schema: any; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts new file mode 100644 index 0000000000..7e762f616c --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ValidationErrorArgument } from '../models/ValidationErrorArgument.model'; +import { ValidationErrorPathInner } from '../models/ValidationErrorPathInner.model'; + +/** + * @public + */ +export interface ValidationError { + [key: string]: any; + + path: Array<ValidationErrorPathInner>; + property: string; + message: string; + instance: any; + name: string; + argument: ValidationErrorArgument; + stack: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts new file mode 100644 index 0000000000..85c9576fd0 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorArgument = any | boolean | number | string; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts new file mode 100644 index 0000000000..4535c735db --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorPathInner = number | string; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts new file mode 100644 index 0000000000..1bc447fa3d --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts @@ -0,0 +1,65 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from '../models/Action.model'; +export * from '../models/ActionExample.model'; +export * from '../models/ActionSchema.model'; +export * from '../models/Autocomplete200Response.model'; +export * from '../models/Autocomplete200ResponseResultsInner.model'; +export * from '../models/Autocomplete400Response.model'; +export * from '../models/AutocompleteRequest.model'; +export * from '../models/CancelTask200Response.model'; +export * from '../models/DryRun200Response.model'; +export * from '../models/DryRun200ResponseAllOf.model'; +export * from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +export * from '../models/DryRun200ResponseAllOfStepsInner.model'; +export * from '../models/DryRunRequest.model'; +export * from '../models/DryRunRequestDirectoryContentsInner.model'; +export * from '../models/DryRunResult.model'; +export * from '../models/DryRunResultLogInner.model'; +export * from '../models/DryRunResultLogInnerBody.model'; +export * from '../models/DryRunResultLogInnerBodyAllOf.model'; +export * from '../models/ErrorError.model'; +export * from '../models/ErrorRequest.model'; +export * from '../models/ErrorResponse.model'; +export * from '../models/JsonPrimitive.model'; +export * from '../models/JsonValue.model'; +export * from '../models/ListTasksResponse.model'; +export * from '../models/ListTemplatingExtensionsResponse.model'; +export * from '../models/ListTemplatingExtensionsResponseGlobals.model'; +export * from '../models/ModelError.model'; +export * from '../models/RetryRequest.model'; +export * from '../models/Scaffold201Response.model'; +export * from '../models/Scaffold400Response.model'; +export * from '../models/ScaffolderScaffoldOptions.model'; +export * from '../models/ScaffolderUsageExample.model'; +export * from '../models/SerializedFile.model'; +export * from '../models/SerializedTask.model'; +export * from '../models/SerializedTaskEvent.model'; +export * from '../models/TaskEventType.model'; +export * from '../models/TaskSecrets.model'; +export * from '../models/TaskSecretsAllOf.model'; +export * from '../models/TaskStatus.model'; +export * from '../models/TemplateFilter.model'; +export * from '../models/TemplateFilterSchema.model'; +export * from '../models/TemplateGlobalFunction.model'; +export * from '../models/TemplateGlobalFunctionSchema.model'; +export * from '../models/TemplateGlobalValue.model'; +export * from '../models/TemplateParameterSchema.model'; +export * from '../models/TemplateParameterSchemaStepsInner.model'; +export * from '../models/ValidationError.model'; +export * from '../models/ValidationErrorArgument.model'; +export * from '../models/ValidationErrorPathInner.model'; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts new file mode 100644 index 0000000000..669dd63878 --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts @@ -0,0 +1,1328 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; +import { EndpointMap } from './apis'; + +export const spec = { + openapi: '3.0.3', + info: { + title: 'scaffolder', + version: '1', + description: + 'The Backstage backend plugin that helps you create new things', + license: { + name: 'Apache-2.0', + url: 'http://www.apache.org/licenses/LICENSE-2.0.html', + }, + contact: {}, + }, + servers: [ + { + url: '/', + }, + ], + components: { + examples: {}, + headers: {}, + parameters: { + createdBy: { + name: 'createdBy', + in: 'query', + description: 'Created by', + required: false, + allowReserved: true, + schema: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + eventsAfter: { + name: 'after', + in: 'query', + description: 'Offset event ID to stream events after.', + required: false, + allowReserved: true, + schema: { + type: 'integer', + }, + }, + kind: { + name: 'kind', + in: 'path', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + limit: { + name: 'limit', + in: 'query', + description: 'Number of records to return in the response.', + required: false, + allowReserved: true, + schema: { + type: 'integer', + minimum: 0, + }, + }, + namespace: { + name: 'namespace', + in: 'path', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + name: { + name: 'name', + in: 'path', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + offset: { + name: 'offset', + in: 'query', + description: 'Number of records to skip in the query page.', + required: false, + allowReserved: true, + schema: { + type: 'integer', + minimum: 0, + }, + }, + order: { + name: 'order', + in: 'query', + description: 'Order', + required: false, + allowReserved: true, + schema: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + status: { + name: 'status', + in: 'query', + description: 'Status', + required: false, + allowReserved: true, + schema: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + taskId: { + name: 'taskId', + in: 'path', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + }, + requestBodies: {}, + responses: { + ErrorResponse: { + description: 'An error response from the backend.', + content: { + 'application/json; charset=utf-8': { + schema: { + $ref: '#/components/schemas/Error', + }, + }, + }, + }, + }, + schemas: { + Action: { + type: 'object', + properties: { + id: { + type: 'string', + }, + description: { + type: 'string', + }, + "'examples'": { + type: 'array', + items: { + $ref: '#/components/schemas/ActionExample', + }, + }, + schema: { + type: 'object', + properties: { + input: { + $ref: '#/components/schemas/JsonObject', + }, + output: { + $ref: '#/components/schemas/JsonObject', + }, + }, + }, + }, + required: ['id'], + description: + 'The response shape for a single action in the `listActions` call to the `scaffolder-backend`', + }, + ActionExample: { + type: 'object', + properties: { + description: { + type: 'string', + }, + example: { + type: 'string', + }, + }, + required: ['description', 'example'], + description: 'A single action example', + }, + DryRunResult: { + type: 'object', + properties: { + log: { + type: 'array', + items: { + type: 'object', + properties: { + body: { + allOf: [ + { + $ref: '#/components/schemas/JsonObject', + }, + { + type: 'object', + properties: { + message: { + type: 'string', + }, + status: { + $ref: '#/components/schemas/TaskStatus', + }, + stepId: { + type: 'string', + }, + }, + required: ['message'], + }, + ], + }, + }, + required: ['body'], + }, + }, + directoryContents: { + type: 'array', + items: { + $ref: '#/components/schemas/SerializedFile', + }, + }, + output: { + $ref: '#/components/schemas/JsonObject', + }, + }, + required: ['log', 'directoryContents', 'output'], + }, + Error: { + type: 'object', + properties: { + error: { + type: 'object', + properties: { + name: { + type: 'string', + }, + message: { + type: 'string', + }, + stack: { + type: 'string', + }, + code: { + type: 'string', + }, + }, + required: ['name', 'message'], + }, + request: { + type: 'object', + properties: { + method: { + type: 'string', + }, + url: { + type: 'string', + }, + }, + required: ['method', 'url'], + }, + response: { + type: 'object', + properties: { + statusCode: { + type: 'number', + }, + }, + required: ['statusCode'], + }, + }, + required: ['error', 'response'], + additionalProperties: {}, + }, + JsonArray: { + type: 'array', + items: { + $ref: '#/components/schemas/JsonValue', + }, + description: 'A type representing all allowed JSON array values.', + }, + JsonObject: { + type: 'object', + properties: {}, + description: 'A type representing all allowed JSON object values.', + additionalProperties: {}, + }, + JsonPrimitive: { + oneOf: [ + { + type: 'boolean', + }, + { + type: 'number', + }, + { + type: 'string', + }, + { + type: 'object', + nullable: true, + }, + ], + description: 'A type representing all allowed JSON primitive values.', + }, + JsonValue: { + oneOf: [ + { + $ref: '#/components/schemas/JsonObject', + }, + { + $ref: '#/components/schemas/JsonArray', + }, + { + $ref: '#/components/schemas/JsonPrimitive', + }, + ], + description: 'A type representing all allowed JSON values.', + }, + ListActionsResponse: { + type: 'array', + items: { + $ref: '#/components/schemas/Action', + }, + description: + 'The response shape for the `listActions` call to the `scaffolder-backend`', + }, + ListTasksResponse: { + type: 'object', + properties: { + tasks: { + type: 'array', + items: { + $ref: '#/components/schemas/SerializedTask', + }, + }, + totalTasks: { + type: 'number', + }, + }, + required: ['tasks'], + description: + 'The response shape for the `listTasks` call to the `scaffolder-backend`', + }, + ListTemplatingExtensionsResponse: { + type: 'object', + properties: { + filters: { + type: 'object', + additionalProperties: { + $ref: '#/components/schemas/TemplateFilter', + }, + }, + globals: { + type: 'object', + properties: { + functions: { + type: 'object', + additionalProperties: { + $ref: '#/components/schemas/TemplateGlobalFunction', + }, + }, + values: { + type: 'object', + additionalProperties: { + $ref: '#/components/schemas/TemplateGlobalValue', + }, + }, + }, + required: ['functions', 'values'], + }, + }, + required: ['filters', 'globals'], + description: + 'The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend`', + }, + ScaffolderScaffoldOptions: { + type: 'object', + properties: { + templateRef: { + type: 'string', + }, + values: { + type: 'object', + additionalProperties: {}, + }, + secrets: { + type: 'object', + additionalProperties: { + type: 'string', + }, + }, + }, + required: ['templateRef', 'values'], + description: + 'The input options to the `scaffold` method of the `ScaffolderClient`.', + }, + ScaffolderUsageExample: { + type: 'object', + properties: { + description: { + type: 'string', + }, + example: { + type: 'string', + }, + notes: { + type: 'string', + }, + }, + required: ['example'], + description: 'A single scaffolder usage example', + }, + SerializedFile: { + type: 'object', + properties: { + path: { + type: 'string', + }, + content: { + type: 'string', + }, + executable: { + type: 'boolean', + }, + symlink: { + type: 'boolean', + }, + }, + required: ['path', 'content'], + }, + SerializedTaskEvent: { + type: 'object', + properties: { + id: { + type: 'integer', + }, + isTaskRecoverable: { + type: 'boolean', + }, + taskId: { + type: 'string', + }, + body: { + allOf: [ + { + $ref: '#/components/schemas/JsonObject', + }, + { + type: 'object', + properties: { + message: { + type: 'string', + }, + status: { + $ref: '#/components/schemas/TaskStatus', + }, + stepId: { + type: 'string', + }, + }, + required: ['message'], + }, + ], + }, + type: { + $ref: '#/components/schemas/TaskEventType', + }, + createdAt: { + type: 'string', + }, + }, + required: ['id', 'taskId', 'body', 'type', 'createdAt'], + description: 'SerializedTaskEvent', + }, + SerializedTask: { + type: 'object', + properties: { + id: { + type: 'string', + }, + spec: { + type: 'object', + }, + status: { + $ref: '#/components/schemas/TaskStatus', + }, + createdAt: { + type: 'string', + }, + lastHeartbeatAt: { + type: 'string', + }, + createdBy: { + type: 'string', + }, + secrets: { + $ref: '#/components/schemas/TaskSecrets', + }, + state: { + $ref: '#/components/schemas/JsonObject', + }, + }, + required: ['id', 'spec', 'status', 'createdAt'], + description: 'SerializedTask', + }, + TaskEventType: { + type: 'string', + description: 'TaskEventType', + enum: ['cancelled', 'completion', 'log', 'recovered'], + }, + TaskSecrets: { + allOf: [ + { + type: 'object', + additionalProperties: { + type: 'string', + }, + }, + { + type: 'object', + properties: { + backstageToken: { + type: 'string', + }, + }, + }, + ], + description: 'TaskSecrets', + }, + TaskStatus: { + type: 'string', + enum: [ + 'cancelled', + 'completed', + 'failed', + 'open', + 'processing', + 'skipped', + ], + description: 'The status of each step of the Task', + }, + TemplateGlobalFunction: { + type: 'object', + properties: { + description: { + type: 'string', + }, + schema: { + type: 'object', + properties: { + arguments: { + type: 'array', + items: { + $ref: '#/components/schemas/JsonObject', + }, + }, + output: { + $ref: '#/components/schemas/JsonObject', + }, + }, + }, + "'examples'": { + type: 'array', + items: { + $ref: '#/components/schemas/ScaffolderUsageExample', + }, + }, + }, + description: + 'The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend`', + }, + TemplateGlobalValue: { + type: 'object', + properties: { + description: { + type: 'string', + }, + value: { + type: 'object', + nullable: true, + }, + }, + required: ['value'], + description: + 'The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend`', + }, + TemplateFilter: { + type: 'object', + properties: { + description: { + type: 'string', + }, + schema: { + type: 'object', + properties: { + input: { + $ref: '#/components/schemas/JsonObject', + }, + arguments: { + type: 'array', + items: { + $ref: '#/components/schemas/JsonObject', + }, + }, + output: { + $ref: '#/components/schemas/JsonObject', + }, + }, + }, + "'examples'": { + type: 'array', + items: { + $ref: '#/components/schemas/ScaffolderUsageExample', + }, + }, + }, + description: + 'The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend`', + }, + TemplateParameterSchema: { + type: 'object', + properties: { + title: { + type: 'string', + }, + description: { + type: 'string', + }, + steps: { + type: 'array', + items: { + type: 'object', + properties: { + title: { + type: 'string', + }, + description: { + type: 'string', + }, + schema: { + type: 'object', + }, + }, + required: ['title', 'schema'], + }, + }, + }, + required: ['title', 'steps'], + description: + 'The shape of each entry of parameters which gets rendered\nas a separate step in the wizard input', + additionalProperties: {}, + }, + ValidationError: { + type: 'object', + properties: { + path: { + type: 'array', + items: { + oneOf: [ + { + type: 'string', + }, + { + type: 'integer', + }, + ], + }, + }, + property: { + type: 'string', + }, + message: { + type: 'string', + }, + instance: { + type: 'object', + }, + name: { + type: 'string', + }, + argument: { + oneOf: [ + { + type: 'boolean', + }, + { + type: 'number', + }, + { + type: 'object', + }, + { + type: 'string', + }, + ], + }, + stack: { + type: 'string', + }, + }, + required: [ + 'path', + 'property', + 'message', + 'schema', + 'instance', + 'name', + 'argument', + 'stack', + ], + additionalProperties: {}, + }, + }, + securitySchemes: { + JWT: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + }, + }, + }, + paths: { + '/v2/templates/{namespace}/{kind}/{name}/parameter-schema': { + get: { + operationId: 'GetTemplateParameterSchema', + description: 'Get template parameter schema.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/TemplateParameterSchema', + }, + }, + }, + }, + '400': { + $ref: '#/components/responses/ErrorResponse', + }, + default: { + $ref: '#/components/responses/ErrorResponse', + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [ + { + $ref: '#/components/parameters/namespace', + }, + { + $ref: '#/components/parameters/kind', + }, + { + $ref: '#/components/parameters/name', + }, + ], + }, + }, + '/v2/actions': { + get: { + operationId: 'ListActions', + description: 'Returns a list of all installed actions.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ListActionsResponse', + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [], + }, + }, + '/v2/tasks': { + get: { + operationId: 'ListTasks', + description: + 'Returns a list of tasks, filtering by ownership and/or status if given.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ListTasksResponse', + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [ + { + $ref: '#/components/parameters/createdBy', + }, + { + $ref: '#/components/parameters/limit', + }, + { + $ref: '#/components/parameters/offset', + }, + { + $ref: '#/components/parameters/order', + }, + { + $ref: '#/components/parameters/status', + }, + ], + }, + post: { + operationId: 'Scaffold', + description: + 'Executes the scaffolding of a component, given a template and its\nparameter values.', + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ScaffolderScaffoldOptions', + }, + }, + }, + }, + responses: { + '201': { + description: 'Created', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + required: ['id'], + }, + }, + }, + }, + '400': { + description: 'Validation errors.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + errors: { + type: 'array', + items: { + $ref: '#/components/schemas/ValidationError', + }, + }, + }, + required: ['errors'], + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [], + }, + }, + '/v2/tasks/{taskId}': { + get: { + operationId: 'GetTask', + description: 'Get a task by ID.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/SerializedTask', + }, + }, + }, + }, + '403': { + $ref: '#/components/responses/ErrorResponse', + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [ + { + $ref: '#/components/parameters/taskId', + }, + ], + }, + }, + '/v2/tasks/{taskId}/cancel': { + post: { + operationId: 'CancelTask', + description: + 'Sends a signal to a task broker to cancel the running task by taskId.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { + $ref: '#/components/schemas/TaskStatus', + }, + }, + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [ + { + $ref: '#/components/parameters/taskId', + }, + ], + }, + }, + '/v2/tasks/{taskId}/retry': { + post: { + operationId: 'Retry', + description: 'Starts the task again from the point where it failed.', + requestBody: { + required: false, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + secrets: { + type: 'object', + additionalProperties: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + responses: { + '201': { + description: 'Ok', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + required: ['id'], + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [ + { + $ref: '#/components/parameters/taskId', + }, + ], + }, + }, + '/v2/tasks/{taskId}/events': { + get: { + operationId: 'StreamLogsPolling', + description: 'Get events for a task by ID.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + $ref: '#/components/schemas/SerializedTaskEvent', + }, + }, + }, + }, + }, + '403': { + $ref: '#/components/responses/ErrorResponse', + }, + }, + parameters: [ + { + $ref: '#/components/parameters/eventsAfter', + }, + { + $ref: '#/components/parameters/taskId', + }, + ], + }, + }, + '/v2/dry-run': { + post: { + operationId: 'DryRun', + description: 'Perform a dry-run of a template', + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + template: { + type: 'object', + }, + values: { + $ref: '#/components/schemas/JsonObject', + }, + secrets: { + type: 'object', + additionalProperties: { + type: 'string', + }, + }, + directoryContents: { + type: 'array', + items: { + type: 'object', + properties: { + path: { + type: 'string', + }, + base64Content: { + type: 'string', + }, + }, + }, + }, + }, + required: ['template', 'values', 'directoryContents'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + allOf: [ + { + $ref: '#/components/schemas/DryRunResult', + }, + { + type: 'object', + properties: { + steps: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + }, + name: { + type: 'string', + }, + action: { + type: 'string', + }, + }, + required: ['id', 'name', 'action'], + additionalProperties: {}, + }, + }, + directoryContents: { + type: 'array', + items: { + type: 'object', + properties: { + path: { + type: 'string', + }, + executable: { + type: 'boolean', + }, + base64Content: { + type: 'string', + }, + }, + required: ['path', 'base64Content'], + }, + }, + }, + required: ['steps'], + }, + ], + }, + }, + }, + }, + '400': { + description: 'Validation errors.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + errors: { + type: 'array', + items: { + $ref: '#/components/schemas/ValidationError', + }, + }, + }, + required: ['errors'], + }, + }, + }, + }, + }, + parameters: [], + }, + }, + '/v2/autocomplete/{provider}/{resource}': { + post: { + operationId: 'Autocomplete', + description: + 'Perform an autocomplete for the given provider and resource.', + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + context: { + type: 'object', + additionalProperties: { + type: 'string', + }, + }, + token: { + type: 'string', + }, + }, + required: ['context', 'token'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + results: { + type: 'array', + items: { + type: 'object', + properties: { + title: { + type: 'string', + }, + id: { + type: 'string', + }, + }, + required: ['id'], + }, + }, + }, + required: ['results'], + }, + }, + }, + }, + '400': { + description: 'Unsupported provider.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { + type: 'string', + }, + name: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + parameters: [ + { + in: 'path', + name: 'provider', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + { + in: 'path', + name: 'resource', + required: true, + allowReserved: true, + schema: { + type: 'string', + }, + }, + ], + }, + }, + '/v2/templating-extensions': { + get: { + operationId: 'ListTemplatingExtensions', + description: + 'Returns a structure describing the available templating extensions.', + responses: { + '200': { + description: 'Ok', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ListTemplatingExtensionsResponse', + }, + }, + }, + }, + }, + security: [ + {}, + { + JWT: [], + }, + ], + parameters: [], + }, + }, + }, +} as const; +export const createOpenApiRouter = async ( + options?: Parameters< + typeof createValidatedOpenApiRouterFromGeneratedEndpointMap + >['1'], +) => + createValidatedOpenApiRouterFromGeneratedEndpointMap<EndpointMap>( + spec, + options, + ); diff --git a/plugins/scaffolder-backend/src/schema/openapi/index.ts b/plugins/scaffolder-backend/src/schema/openapi/index.ts new file mode 100644 index 0000000000..196aad553a --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './generated'; 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 679ac44640..467b590bed 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import { DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager } from '@backstage/backend-defaults/database'; import { ConfigReader } from '@backstage/config'; +import express from 'express'; import request from 'supertest'; import ObservableImpl from 'zen-observable'; @@ -41,6 +42,7 @@ import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { JsonValue } from '@backstage/types'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { wrapServer } from '@backstage/backend-openapi-utils/testUtils'; import { mockCredentials, mockErrorHandler, @@ -56,7 +58,7 @@ import { } from '@backstage/plugin-scaffolder-node/alpha'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; import { DatabaseService } from '@backstage/backend-plugin-api'; - +import { createDebugLogAction } from '../scaffolder/actions/builtin'; import { ScmIntegrations } from '@backstage/integration'; import { extractFilterMetadata, @@ -77,7 +79,10 @@ function createDatabase(): DatabaseService { }, }, }), - ).forPlugin('scaffolder'); + ).forPlugin('scaffolder', { + logger: mockServices.logger.mock(), + lifecycle: mockServices.lifecycle.mock(), + }); } const config = new ConfigReader({}); @@ -239,11 +244,20 @@ const createTestRouter = async ( }, handler: async () => {}, }), + createDebugLogAction(), ], }); router.use(mockErrorHandler()); - return { router, logger, taskBroker, permissions, catalog }; + const wrappedRouter = await wrapServer(express().use(router)); + return { + router: wrappedRouter, + unwrappedRouter: router, + logger, + taskBroker, + permissions, + catalog, + }; }; describe('scaffolder router', () => { @@ -259,7 +273,7 @@ describe('scaffolder router', () => { const response = await request(router).get('/v2/actions').send(); expect(response.status).toEqual(200); expect(response.body[0].id).toBeDefined(); - expect(response.body.length).toBe(1); + expect(response.body.length).toBe(2); }); }); @@ -701,7 +715,10 @@ describe('scaffolder router', () => { }, }); - console.log(status, body); + expect(status).toBe(201); + expect(body).toMatchObject({ + id: expect.any(String), + }); expect(logger.info).toHaveBeenCalledTimes(1); expect(logger.info).toHaveBeenCalledWith( 'Scaffolding task for template:default/create-react-app-template created by user:default/mock', @@ -945,6 +962,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', () => { @@ -966,11 +1013,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(); + const { unwrappedRouter: 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[]; }>; @@ -1055,7 +1143,17 @@ 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(); + const { unwrappedRouter: 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[]; }>; @@ -1120,6 +1218,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[]; }>; @@ -1180,6 +1288,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[]; }>; @@ -1206,6 +1324,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', () => { @@ -1233,6 +1385,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', () => { @@ -1266,7 +1447,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ it('should call the autocomplete handler', async () => { const handleAutocompleteRequest = jest.fn().mockResolvedValue({ - results: [{ title: 'blob' }], + results: [{ id: 'a-random-id', title: 'blob' }], }); const { router } = await createTestRouter({ @@ -1287,7 +1468,9 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.status).toEqual(200); - expect(response.body).toEqual({ results: [{ title: 'blob' }] }); + expect(response.body).toEqual({ + results: [{ id: 'a-random-id', title: 'blob' }], + }); expect(handleAutocompleteRequest).toHaveBeenCalledWith({ token: mockToken, context, diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 0ea6293f36..e8b9f04797 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, @@ -75,7 +79,6 @@ import { } from '@backstage/plugin-scaffolder-node/alpha'; import { HumanDuration, JsonObject } from '@backstage/types'; import express from 'express'; -import Router from 'express-promise-router'; import { validate } from 'jsonschema'; import { Duration } from 'luxon'; import { pathToFileURL } from 'url'; @@ -89,15 +92,19 @@ import { import { createDryRunner } from '../scaffolder/dryrun'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; -import { checkPermission } from '../util/checkPermissions'; +import { createOpenApiRouter } from '../schema/openapi'; +import { + checkPermission, + checkTaskPermission, + getAuthorizeConditions, +} from '../util/checkPermissions'; import { findTemplate, getEntityBaseUrl, getWorkingDirectory, - parseNumberParam, parseStringsParam, } from './helpers'; -import { scaffolderActionRules, scaffolderTemplateRules } from './rules'; + import { convertFiltersToRecord, convertGlobalsToRecord, @@ -107,6 +114,9 @@ import { } from '../util/templating'; import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters'; import { + ScaffolderPermissionRuleInput, + TaskPermissionRuleInput, + isTaskPermissionRuleInput, ActionPermissionRuleInput, isActionPermissionRuleInput, isTemplatePermissionRuleInput, @@ -114,6 +124,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 +157,7 @@ export interface RouterOptions { | CreatedTemplateGlobal[]; additionalWorkspaceProviders?: Record<string, WorkspaceProvider>; permissions?: PermissionsService; - permissionRules?: Array< - TemplatePermissionRuleInput | ActionPermissionRuleInput - >; + permissionRules?: Array<ScaffolderPermissionRuleInput>; auth: AuthService; httpAuth: HttpAuthService; events?: EventsService; @@ -170,7 +186,7 @@ const readDuration = ( export async function createRouter( options: RouterOptions, ): Promise<express.Router> { - const router = Router(); + const router = await createOpenApiRouter(); // Be generous in upload size to support a wide range of templates in dry-run mode. router.use(express.json({ limit: '10MB' })); @@ -312,15 +328,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 +359,11 @@ export async function createRouter( permissions: scaffolderActionPermissions, rules: actionRules, }, + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, + permissions: scaffolderTaskPermissions, + rules: taskRules, + }, ], permissions: scaffolderPermissions, }); @@ -373,8 +403,10 @@ export async function createRouter( description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ - title: schema.title ?? 'Please enter the following information', - description: schema.description, + title: + (schema.title as string) ?? + 'Please enter the following information', + description: schema.description as string, schema, })), EXPERIMENTAL_formDecorators: @@ -532,11 +564,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( @@ -561,8 +588,14 @@ export async function createRouter( }; }); - const limit = parseNumberParam(req.query.limit, 'limit'); - const offset = parseNumberParam(req.query.offset, 'offset'); + const { limit, offset } = req.query; + + const taskPermissionFilters = await getAuthorizeConditions({ + credentials: credentials, + permission: taskReadPermission, + permissionService: permissions, + transformConditions: taskTransformConditions, + }); const tasks = await taskBroker.list({ filters: { @@ -571,9 +604,10 @@ export async function createRouter( }, order, pagination: { - limit: limit ? limit[0] : undefined, - offset: offset ? offset[0] : undefined, + limit, + offset, }, + 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({ @@ -696,8 +747,10 @@ export async function createRouter( await auditorEvent?.fail({ error: err }); throw err; } - }) - .get('/v2/tasks/:taskId/eventstream', async (req, res) => { + }); + (router as express.Router).get( + '/v2/tasks/:taskId/eventstream', + async (req, res) => { const { taskId } = req.params; const auditorEvent = await auditor?.createEvent({ @@ -711,10 +764,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 = @@ -768,7 +825,9 @@ export async function createRouter( await auditorEvent?.fail({ error: err }); throw err; } - }) + }, + ); + router .get('/v2/tasks/:taskId/events', async (req, res) => { const { taskId } = req.params; @@ -783,10 +842,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 +1086,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/.eslintrc.js b/plugins/scaffolder-common/.eslintrc.js index e2a53a6ad2..c8ec42e57a 100644 --- a/plugins/scaffolder-common/.eslintrc.js +++ b/plugins/scaffolder-common/.eslintrc.js @@ -1 +1,10 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + overrides: [ + { + files: ['src/schema/openapi/generated/models/*.model.ts'], + rules: { + '@typescript-eslint/no-redeclare': 'off', + }, + }, + ], +}); diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 5f1ed60113..ef8efc3273 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-common +## 1.7.0-next.0 + +### Minor Changes + +- c08cbc4: Move Scaffolder API to OpenAPI + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.1 + +## 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..2801c519b2 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.7.0-next.0", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", @@ -61,10 +61,20 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", - "@backstage/types": "workspace:^" + "@backstage/types": "workspace:^", + "@microsoft/fetch-event-source": "^2.0.1", + "@types/json-schema": "^7.0.9", + "cross-fetch": "^4.0.0", + "json-schema": "^0.4.0", + "uri-template": "^2.0.0", + "zen-observable": "^0.10.0" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", + "msw": "^1.0.0" } } 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/report.api.md b/plugins/scaffolder-common/report.api.md index 455921c085..c6c5141cf2 100644 --- a/plugins/scaffolder-common/report.api.md +++ b/plugins/scaffolder-common/report.api.md @@ -7,15 +7,353 @@ import { Entity } from '@backstage/catalog-model'; import type { EntityMeta } from '@backstage/catalog-model'; import type { JsonArray } from '@backstage/types'; import { JsonObject } from '@backstage/types'; -import type { JsonValue } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; +import { JsonValue } from '@backstage/types'; import { KindValidator } from '@backstage/catalog-model'; +import { Observable } from '@backstage/types'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import type { UserEntity } from '@backstage/catalog-model'; +// @public +export type Action = { + id: string; + description?: string; + schema?: { + input?: JSONSchema7; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + // @public export const isTemplateEntityV1beta3: ( entity: Entity, ) => entity is TemplateEntityV1beta3; +// @public +export type ListActionsResponse = Array<Action>; + +// @public +export type ListTemplatingExtensionsResponse = { + filters: Record<string, TemplateFilter>; + globals: { + functions: Record<string, TemplateGlobalFunction>; + values: Record<string, TemplateGlobalValue>; + }; +}; + +// @public +export type LogEvent = { + type: TaskEventType; + body: { + message: string; + stepId?: string; + status?: ScaffolderTaskStatus; + }; + createdAt: string; + id: number; + taskId: string; +}; + +// @public +export interface ScaffolderApi { + // (undocumented) + autocomplete?( + request: { + token: string; + provider: string; + resource: string; + context: Record<string, string>; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ + results: { + title?: string; + id: string; + }[]; + }>; + cancelTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ + status?: ScaffolderTaskStatus; + }>; + // (undocumented) + dryRun?( + request: ScaffolderDryRunOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderDryRunResponse>; + // (undocumented) + getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise<ScaffolderGetIntegrationsListResponse>; + // (undocumented) + getTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderTask>; + // (undocumented) + getTemplateParameterSchema( + templateRef: string, + options?: ScaffolderRequestOptions, + ): Promise<TemplateParameterSchema>; + listActions(options?: ScaffolderRequestOptions): Promise<ListActionsResponse>; + // (undocumented) + listTasks?( + request: { + filterByOwnership: 'owned' | 'all'; + limit?: number; + offset?: number; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ + tasks: ScaffolderTask[]; + totalTasks?: number; + }>; + listTemplatingExtensions?( + options?: ScaffolderRequestOptions, + ): Promise<ListTemplatingExtensionsResponse>; + retry?( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ + id: string; + }>; + scaffold( + request: ScaffolderScaffoldOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderScaffoldResponse>; + // (undocumented) + streamLogs( + request: ScaffolderStreamLogsOptions, + options?: ScaffolderRequestOptions, + ): Observable<LogEvent>; +} + +// @public +export class ScaffolderClient implements ScaffolderApi { + constructor(options: { + discoveryApi: { + getBaseUrl(pluginId: string): Promise<string>; + }; + fetchApi: { + fetch: typeof fetch; + }; + identityApi?: { + getBackstageIdentity(): Promise<{ + type: 'user'; + userEntityRef: string; + ownershipEntityRefs: string[]; + }>; + }; + scmIntegrationsApi: ScmIntegrationRegistry; + useLongPollingLogs?: boolean; + }); + autocomplete({ + token, + resource, + provider, + context, + }: { + token: string; + provider: string; + resource: string; + context: Record<string, string>; + }): Promise<{ + results: { + title?: string; + id: string; + }[]; + }>; + cancelTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ + status?: ScaffolderTaskStatus; + }>; + // (undocumented) + dryRun( + request: ScaffolderDryRunOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderDryRunResponse>; + // (undocumented) + getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise<ScaffolderGetIntegrationsListResponse>; + // (undocumented) + getTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderTask>; + // (undocumented) + getTemplateParameterSchema( + templateRef: string, + options?: ScaffolderRequestOptions, + ): Promise<TemplateParameterSchema>; + listActions(options?: ScaffolderRequestOptions): Promise<ListActionsResponse>; + // (undocumented) + listTasks( + request: { + filterByOwnership: 'owned' | 'all'; + limit?: number; + offset?: number; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ + tasks: ScaffolderTask[]; + totalTasks?: number; + }>; + listTemplatingExtensions( + options?: ScaffolderRequestOptions, + ): Promise<ListTemplatingExtensionsResponse>; + retry?( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ + id: string; + }>; + scaffold( + request: ScaffolderScaffoldOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderScaffoldResponse>; + // (undocumented) + streamLogs( + request: ScaffolderStreamLogsOptions, + options?: ScaffolderRequestOptions, + ): Observable<LogEvent>; +} + +// @public (undocumented) +export interface ScaffolderDryRunOptions { + // (undocumented) + directoryContents: { + path: string; + base64Content: string; + }[]; + // (undocumented) + secrets?: Record<string, string>; + // (undocumented) + template: TemplateEntityV1beta3; + // (undocumented) + values: JsonObject; +} + +// @public (undocumented) +export interface ScaffolderDryRunResponse { + // (undocumented) + directoryContents: Array<{ + path: string; + base64Content: string; + executable?: boolean; + }>; + // (undocumented) + log: Array<Pick<LogEvent, 'body'>>; + // (undocumented) + output: ScaffolderTaskOutput; + // (undocumented) + steps: TaskStep[]; +} + +// @public +export interface ScaffolderGetIntegrationsListOptions { + // (undocumented) + allowedHosts: string[]; +} + +// @public +export interface ScaffolderGetIntegrationsListResponse { + // (undocumented) + integrations: { + type: string; + title: string; + host: string; + }[]; +} + +// @public (undocumented) +export type ScaffolderOutputLink = { + title?: string; + icon?: string; + url?: string; + entityRef?: string; +}; + +// @public (undocumented) +export type ScaffolderOutputText = { + title?: string; + icon?: string; + content?: string; + default?: boolean; +}; + +// @public +export interface ScaffolderRequestOptions { + // (undocumented) + token?: string; +} + +// @public +export interface ScaffolderScaffoldOptions { + // (undocumented) + secrets?: Record<string, string>; + // (undocumented) + templateRef: string; + // (undocumented) + values: Record<string, JsonValue>; +} + +// @public +export interface ScaffolderScaffoldResponse { + // (undocumented) + taskId: string; +} + +// @public +export interface ScaffolderStreamLogsOptions { + // (undocumented) + after?: number; + // (undocumented) + isTaskRecoverable?: boolean; + // (undocumented) + taskId: string; +} + +// @public +export type ScaffolderTask = { + id: string; + spec: TaskSpec; + status: ScaffolderTaskStatus; + lastHeartbeatAt?: string; + createdAt: string; +}; + +// @public (undocumented) +export type ScaffolderTaskOutput = { + links?: ScaffolderOutputLink[]; + text?: ScaffolderOutputText[]; +} & { + [key: string]: unknown; +}; + +// @public (undocumented) +export type ScaffolderTaskStatus = + | 'cancelled' + | 'completed' + | 'failed' + | 'open' + | 'processing' + | 'skipped'; + +// @public +export type ScaffolderUsageExample = { + description?: string; + example: string; + notes?: string; +}; + +// @public (undocumented) +export type TaskEventType = 'cancelled' | 'completion' | 'log' | 'recovered'; + // @public export type TaskRecoverStrategy = 'none' | 'startOver'; @@ -94,6 +432,33 @@ export interface TemplateEntityV1beta3 extends Entity { // @public export const templateEntityV1beta3Validator: KindValidator; +// @public +export type TemplateFilter = { + description?: string; + schema?: { + input?: JSONSchema7; + arguments?: JSONSchema7[]; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + +// @public +export type TemplateGlobalFunction = { + description?: string; + schema?: { + arguments?: JSONSchema7[]; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + +// @public +export type TemplateGlobalValue = { + description?: string; + value: JsonValue; +}; + // @public export type TemplateInfo = { entityRef: string; @@ -103,6 +468,22 @@ export type TemplateInfo = { }; }; +// @public +export type TemplateParameterSchema = { + title: string; + description?: string; + presentation?: TemplatePresentationV1beta3; + steps: Array<{ + title: string; + description?: string; + schema: JsonObject; + }>; + EXPERIMENTAL_formDecorators?: { + id: string; + input?: JsonObject; + }[]; +}; + // @public export interface TemplateParametersV1beta3 extends JsonObject { // (undocumented) diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder-common/src/ScaffolderClient.test.ts similarity index 97% rename from plugins/scaffolder/src/api.test.ts rename to plugins/scaffolder-common/src/ScaffolderClient.test.ts index 1df2dacb17..03064d7086 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder-common/src/ScaffolderClient.test.ts @@ -14,12 +14,15 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; -import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; +import { + MockFetchApi, + mockApis, + registerMswTestHooks, +} from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { ScaffolderClient } from './api'; +import { ScaffolderClient } from './ScaffolderClient'; import { fetchEventSource } from '@microsoft/fetch-event-source'; jest.mock('@microsoft/fetch-event-source'); @@ -31,6 +34,17 @@ const server = setupServer(); describe('api', () => { registerMswTestHooks(server); + const githubIntegrationConfig = mockApis.config({ + data: { + integrations: { + github: [ + { + host: 'hello.com', + }, + ], + }, + }, + }); const mockBaseUrl = 'http://backstage/api'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; @@ -43,15 +57,7 @@ describe('api', () => { }; const scmIntegrationsApi = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - github: [ - { - host: 'hello.com', - }, - ], - }, - }), + githubIntegrationConfig, ); let apiClient: ScaffolderClient; diff --git a/plugins/scaffolder-common/src/ScaffolderClient.ts b/plugins/scaffolder-common/src/ScaffolderClient.ts new file mode 100644 index 0000000000..d40f7a4637 --- /dev/null +++ b/plugins/scaffolder-common/src/ScaffolderClient.ts @@ -0,0 +1,426 @@ +/* + * 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 { parseEntityRef } from '@backstage/catalog-model'; +import { ResponseError } from '@backstage/errors'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { Observable } from '@backstage/types'; +import { + EventSourceMessage, + fetchEventSource, +} from '@microsoft/fetch-event-source'; +import ObservableImpl from 'zen-observable'; + +import { type TemplateParameterSchema } from './TemplateEntityV1beta3'; +import { + ListActionsResponse, + ListTemplatingExtensionsResponse, + LogEvent, + ScaffolderApi, + ScaffolderDryRunOptions, + ScaffolderDryRunResponse, + ScaffolderGetIntegrationsListOptions, + ScaffolderGetIntegrationsListResponse, + ScaffolderRequestOptions, + ScaffolderScaffoldOptions, + ScaffolderScaffoldResponse, + ScaffolderStreamLogsOptions, + ScaffolderTask, +} from './api'; +import { DefaultApiClient, TaskStatus, TypedResponse } from './schema/openapi'; + +/** + * An API to interact with the scaffolder backend. + * + * @public + */ +export class ScaffolderClient implements ScaffolderApi { + private readonly apiClient: DefaultApiClient; + private readonly discoveryApi: { + getBaseUrl(pluginId: string): Promise<string>; + }; + private readonly scmIntegrationsApi: ScmIntegrationRegistry; + private readonly fetchApi: { fetch: typeof fetch }; + private readonly identityApi?: { + getBackstageIdentity(): Promise<{ + type: 'user'; + userEntityRef: string; + ownershipEntityRefs: string[]; + }>; + }; + private readonly useLongPollingLogs: boolean; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise<string> }; + fetchApi: { fetch: typeof fetch }; + identityApi?: { + getBackstageIdentity(): Promise<{ + type: 'user'; + userEntityRef: string; + ownershipEntityRefs: string[]; + }>; + }; + scmIntegrationsApi: ScmIntegrationRegistry; + useLongPollingLogs?: boolean; + }) { + this.apiClient = new DefaultApiClient(options); + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi ?? { fetch }; + this.scmIntegrationsApi = options.scmIntegrationsApi; + this.useLongPollingLogs = options.useLongPollingLogs ?? false; + this.identityApi = options.identityApi; + } + + /** + * {@inheritdoc ScaffolderApi.listTasks} + */ + async listTasks( + request: { + filterByOwnership: 'owned' | 'all'; + limit?: number; + offset?: number; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }> { + if (!this.identityApi) { + throw new Error( + 'IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method', + ); + } + + const { userEntityRef } = await this.identityApi.getBackstageIdentity(); + + return await this.requestRequired( + await this.apiClient.listTasks( + { + query: { + createdBy: + request.filterByOwnership === 'owned' + ? [userEntityRef] + : undefined, + limit: request.limit, + offset: request.offset, + }, + }, + options, + ), + ); + } + + async getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise<ScaffolderGetIntegrationsListResponse> { + const integrations = [ + ...this.scmIntegrationsApi.azure.list(), + ...this.scmIntegrationsApi.bitbucket + .list() + .filter( + item => + !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && + !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host), + ), + ...this.scmIntegrationsApi.bitbucketCloud.list(), + ...this.scmIntegrationsApi.bitbucketServer.list(), + ...this.scmIntegrationsApi.gerrit.list(), + ...this.scmIntegrationsApi.gitea.list(), + ...this.scmIntegrationsApi.github.list(), + ...this.scmIntegrationsApi.gitlab.list(), + ] + .map(c => ({ type: c.type, title: c.title, host: c.config.host })) + .filter(c => options.allowedHosts.includes(c.host)); + + return { + integrations, + }; + } + + /** + * {@inheritdoc ScaffolderApi.getTemplateParameterSchema} + */ + async getTemplateParameterSchema( + templateRef: string, + options?: ScaffolderRequestOptions, + ): Promise<TemplateParameterSchema> { + return await this.requestRequired( + await this.apiClient.getTemplateParameterSchema( + { + path: parseEntityRef(templateRef, { + defaultKind: 'template', + }), + }, + options, + ), + ); + } + + /** + * {@inheritdoc ScaffolderApi.scaffold} + */ + async scaffold( + request: ScaffolderScaffoldOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderScaffoldResponse> { + const response = await this.apiClient.scaffold( + { + body: request, + }, + options, + ); + + if (response.status !== 201) { + const status = `${response.status} ${response.statusText}`; + const body = await response.text(); + throw new Error(`Backend request failed, ${status} ${body.trim()}`); + } + + const { id } = await response.json(); + return { taskId: id }; + } + + /** + * {@inheritdoc ScaffolderApi.getTask} + */ + async getTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderTask> { + return await this.requestRequired( + await this.apiClient.getTask( + { + path: { taskId }, + }, + options, + ), + ); + } + + /** + * {@inheritdoc ScaffolderApi.streamLogs} + */ + streamLogs( + request: ScaffolderStreamLogsOptions, + options?: ScaffolderRequestOptions, + ): Observable<LogEvent> { + if (this.useLongPollingLogs) { + return this.streamLogsPolling(request, options); + } + + return this.streamLogsEventStream(request); + } + + /** + * {@inheritdoc ScaffolderApi.dryRun} + */ + async dryRun( + request: ScaffolderDryRunOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderDryRunResponse> { + return await this.requestRequired( + await this.apiClient.dryRun( + { + body: { + template: request.template, + values: request.values, + secrets: request.secrets, + directoryContents: request.directoryContents, + }, + }, + options, + ), + ); + } + + private streamLogsEventStream({ + isTaskRecoverable, + taskId, + after, + }: ScaffolderStreamLogsOptions): Observable<LogEvent> { + return new ObservableImpl(subscriber => { + const params = new URLSearchParams(); + if (after !== undefined) { + params.set('after', String(Number(after))); + } + + this.discoveryApi.getBaseUrl('scaffolder').then( + baseUrl => { + const url = `${baseUrl}/v2/tasks/${encodeURIComponent( + taskId, + )}/eventstream`; + + const processEvent = (event: any) => { + if (event.data) { + try { + subscriber.next(JSON.parse(event.data)); + } catch (ex) { + subscriber.error(ex); + } + } + }; + + const ctrl = new AbortController(); + void fetchEventSource(url, { + fetch: this.fetchApi.fetch, + signal: ctrl.signal, + onmessage(e: EventSourceMessage) { + if (e.event === 'log') { + processEvent(e); + return; + } else if (e.event === 'completion' && !isTaskRecoverable) { + processEvent(e); + subscriber.complete(); + ctrl.abort(); + return; + } + processEvent(e); + }, + onerror(err) { + subscriber.error(err); + }, + }); + }, + error => { + subscriber.error(error); + }, + ); + }); + } + + private streamLogsPolling( + { + taskId, + after: inputAfter, + }: { + taskId: string; + after?: number; + }, + options?: ScaffolderRequestOptions, + ): Observable<LogEvent> { + let after = inputAfter; + + return new ObservableImpl(subscriber => { + (async () => { + while (!subscriber.closed) { + const response = await this.apiClient.streamLogsPolling( + { + path: { taskId }, + query: { after }, + }, + options, + ); + + if (!response.ok) { + // wait for one second to not run into an + await new Promise(resolve => setTimeout(resolve, 1000)); + continue; + } + + const logs = (await response.json()) as LogEvent[]; + + for (const event of logs) { + after = Number(event.id); + + subscriber.next(event); + + if (event.type === 'completion') { + subscriber.complete(); + return; + } + } + } + })(); + }); + } + + /** + * {@inheritdoc ScaffolderApi.listActions} + */ + async listActions( + options?: ScaffolderRequestOptions, + ): Promise<ListActionsResponse> { + return await this.requestRequired( + await this.apiClient.listActions(null as any, options), + ); + } + + /** + * {@inheritdoc ScaffolderApi.listTemplatingExtensions} + */ + async listTemplatingExtensions( + options?: ScaffolderRequestOptions, + ): Promise<ListTemplatingExtensionsResponse> { + return await this.requestRequired( + await this.apiClient.listTemplatingExtensions(null as any, options), + ); + } + + /** + * {@inheritdoc ScaffolderApi.cancelTask} + */ + async cancelTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ status?: TaskStatus }> { + return await this.requestRequired( + await this.apiClient.cancelTask({ path: { taskId } }, options), + ); + } + + /** + * {@inheritdoc ScaffolderApi.retry} + */ + async retry?( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ id: string }> { + return await this.requestRequired( + await this.apiClient.retry({ body: {}, path: { taskId } }, options), + ); + } + + /** + * {@inheritdoc ScaffolderApi.retry} + */ + async autocomplete({ + token, + resource, + provider, + context, + }: { + token: string; + provider: string; + resource: string; + context: Record<string, string>; + }): Promise<{ results: { title?: string; id: string }[] }> { + return await this.requestRequired( + await this.apiClient.autocomplete({ + path: { provider, resource }, + body: { token, context }, + }), + ); + } + + // + // Private methods + // + + private async requestRequired<T>(response: TypedResponse<T>): Promise<T> { + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return response.json(); + } +} diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 304057af77..1851b7e70f 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -142,6 +142,24 @@ export interface TemplateEntityStepV1beta3 extends JsonObject { 'backstage:permissions'?: TemplatePermissionsV1beta3; } +/** + * The shape of each entry of parameters which gets rendered + * as a separate step in the wizard input + * + * @public + */ +export type TemplateParameterSchema = { + title: string; + description?: string; + presentation?: TemplatePresentationV1beta3; + steps: Array<{ + title: string; + description?: string; + schema: JsonObject; + }>; + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; +}; + /** * Parameter that is part of a Template Entity. * diff --git a/plugins/scaffolder-common/src/api.ts b/plugins/scaffolder-common/src/api.ts new file mode 100644 index 0000000000..5425607d34 --- /dev/null +++ b/plugins/scaffolder-common/src/api.ts @@ -0,0 +1,337 @@ +/* + * 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 { JsonObject, JsonValue, Observable } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; +import { TaskSpec, TaskStep } from './TaskSpec'; +import type { + TemplateEntityV1beta3, + TemplateParameterSchema, +} from './TemplateEntityV1beta3'; +import type { + TaskEventType, + TaskStatus as ScaffolderTaskStatus, +} from './schema/openapi'; + +export type { ScaffolderTaskStatus, TaskEventType }; + +/** + * Options you can pass into a Scaffolder request for additional information. + * + * @public + */ +export interface ScaffolderRequestOptions { + token?: string; +} + +/** + * The shape of each task returned from the `scaffolder-backend` + * + * @public + */ +export type ScaffolderTask = { + id: string; + spec: TaskSpec; + status: ScaffolderTaskStatus; + lastHeartbeatAt?: string; + createdAt: string; +}; + +/** + * A single scaffolder usage example + * + * @public + */ +export type ScaffolderUsageExample = { + description?: string; + example: string; + notes?: string; +}; + +/** + * The response shape for a single action in the `listActions` call to the `scaffolder-backend` + * + * @public + */ +export type Action = { + id: string; + description?: string; + schema?: { + input?: JSONSchema7; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + +/** + * The response shape for the `listActions` call to the `scaffolder-backend` + * + * @public + */ +export type ListActionsResponse = Array<Action>; + +/** + * The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend` + * + * @public + */ +export type TemplateFilter = { + description?: string; + schema?: { + input?: JSONSchema7; + arguments?: JSONSchema7[]; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + +/** + * The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend` + * + * @public + */ +export type TemplateGlobalFunction = { + description?: string; + schema?: { + arguments?: JSONSchema7[]; + output?: JSONSchema7; + }; + examples?: ScaffolderUsageExample[]; +}; + +/** + * The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend` + * + * @public + */ +export type TemplateGlobalValue = { + description?: string; + value: JsonValue; +}; + +/** + * The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend` + * + * @public + */ +export type ListTemplatingExtensionsResponse = { + filters: Record<string, TemplateFilter>; + globals: { + functions: Record<string, TemplateGlobalFunction>; + values: Record<string, TemplateGlobalValue>; + }; +}; + +/** @public */ +export type ScaffolderOutputLink = { + title?: string; + icon?: string; + url?: string; + entityRef?: string; +}; + +/** @public */ +export type ScaffolderOutputText = { + title?: string; + icon?: string; + content?: string; + default?: boolean; +}; + +/** @public */ +export type ScaffolderTaskOutput = { + links?: ScaffolderOutputLink[]; + text?: ScaffolderOutputText[]; +} & { + [key: string]: unknown; +}; + +/** + * The shape of a `LogEvent` message from the `scaffolder-backend` + * + * @public + */ +export type LogEvent = { + type: TaskEventType; + body: { + message: string; + stepId?: string; + status?: ScaffolderTaskStatus; + }; + createdAt: string; + id: number; + taskId: string; +}; + +/** + * The input options to the `scaffold` method of the `ScaffolderClient`. + * + * @public + */ +export interface ScaffolderScaffoldOptions { + templateRef: string; + values: Record<string, JsonValue>; + secrets?: Record<string, string>; +} + +/** + * The response shape of the `scaffold` method of the `ScaffolderClient`. + * + * @public + */ +export interface ScaffolderScaffoldResponse { + taskId: string; +} + +/** + * The arguments for `getIntegrationsList`. + * + * @public + */ +export interface ScaffolderGetIntegrationsListOptions { + allowedHosts: string[]; +} + +/** + * The response shape for `getIntegrationsList`. + * + * @public + */ +export interface ScaffolderGetIntegrationsListResponse { + integrations: { type: string; title: string; host: string }[]; +} + +/** + * The input options to the `streamLogs` method of the `ScaffolderClient`. + * + * @public + */ +export interface ScaffolderStreamLogsOptions { + isTaskRecoverable?: boolean; + taskId: string; + after?: number; +} + +/** @public */ +export interface ScaffolderDryRunOptions { + template: TemplateEntityV1beta3; + values: JsonObject; + secrets?: Record<string, string>; + directoryContents: { path: string; base64Content: string }[]; +} + +/** @public */ +export interface ScaffolderDryRunResponse { + directoryContents: Array<{ + path: string; + base64Content: string; + executable?: boolean; + }>; + log: Array<Pick<LogEvent, 'body'>>; + steps: TaskStep[]; + output: ScaffolderTaskOutput; +} +/** + * An API to interact with the scaffolder backend. + * + * @public + */ +export interface ScaffolderApi { + getTemplateParameterSchema( + templateRef: string, + options?: ScaffolderRequestOptions, + ): Promise<TemplateParameterSchema>; + + /** + * Executes the scaffolding of a component, given a template and its + * parameter values. + * + * @param options - The {@link ScaffolderScaffoldOptions} the scaffolding. + */ + scaffold( + request: ScaffolderScaffoldOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderScaffoldResponse>; + + getTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderTask>; + + /** + * Sends a signal to a task broker to cancel the running task by taskId. + * + * @param taskId - the id of the task + */ + cancelTask( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ status?: ScaffolderTaskStatus }>; + + /** + * Starts the task again from the point where it failed. + * + * @param taskId - the id of the task + */ + retry?( + taskId: string, + options?: ScaffolderRequestOptions, + ): Promise<{ id: string }>; + + listTasks?( + request: { + filterByOwnership: 'owned' | 'all'; + limit?: number; + offset?: number; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }>; + + getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise<ScaffolderGetIntegrationsListResponse>; + + /** + * Returns a list of all installed actions. + */ + listActions(options?: ScaffolderRequestOptions): Promise<ListActionsResponse>; + + /** + * Returns a structure describing the available templating extensions. + */ + listTemplatingExtensions?( + options?: ScaffolderRequestOptions, + ): Promise<ListTemplatingExtensionsResponse>; + + streamLogs( + request: ScaffolderStreamLogsOptions, + options?: ScaffolderRequestOptions, + ): Observable<LogEvent>; + + dryRun?( + request: ScaffolderDryRunOptions, + options?: ScaffolderRequestOptions, + ): Promise<ScaffolderDryRunResponse>; + + autocomplete?( + request: { + token: string; + provider: string; + resource: string; + context: Record<string, string>; + }, + options?: ScaffolderRequestOptions, + ): Promise<{ results: { title?: string; id: string }[] }>; +} diff --git a/plugins/scaffolder-common/src/index.ts b/plugins/scaffolder-common/src/index.ts index 4d9b5e39c6..ad37973a7b 100644 --- a/plugins/scaffolder-common/src/index.ts +++ b/plugins/scaffolder-common/src/index.ts @@ -30,7 +30,12 @@ export type { TemplatePresentationV1beta3, TemplateEntityV1beta3, TemplateEntityStepV1beta3, + TemplateParameterSchema, TemplateParametersV1beta3, TemplatePermissionsV1beta3, TemplateRecoveryV1beta3, } from './TemplateEntityV1beta3'; + +export * from './ScaffolderClient'; + +export * from './api'; 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-common/src/schema/openapi/generated/apis/Api.client.ts b/plugins/scaffolder-common/src/schema/openapi/generated/apis/Api.client.ts new file mode 100644 index 0000000000..ca5ae10b8f --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/apis/Api.client.ts @@ -0,0 +1,454 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import { pluginId } from '../pluginId'; +import * as parser from 'uri-template'; +import { Action } from '../models/Action.model'; +import { Autocomplete200Response } from '../models/Autocomplete200Response.model'; +import { AutocompleteRequest } from '../models/AutocompleteRequest.model'; +import { CancelTask200Response } from '../models/CancelTask200Response.model'; +import { DryRun200Response } from '../models/DryRun200Response.model'; +import { DryRunRequest } from '../models/DryRunRequest.model'; +import { ListTasksResponse } from '../models/ListTasksResponse.model'; +import { ListTemplatingExtensionsResponse } from '../models/ListTemplatingExtensionsResponse.model'; +import { RetryRequest } from '../models/RetryRequest.model'; +import { Scaffold201Response } from '../models/Scaffold201Response.model'; +import { ScaffolderScaffoldOptions } from '../models/ScaffolderScaffoldOptions.model'; +import { SerializedTask } from '../models/SerializedTask.model'; +import { SerializedTaskEvent } from '../models/SerializedTaskEvent.model'; +import { TemplateParameterSchema } from '../models/TemplateParameterSchema.model'; + +/** + * Wraps the Response type to convey a type on the json call. + * + * @public + */ +export type TypedResponse<T> = Omit<Response, 'json'> & { + json: () => Promise<T>; +}; + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} +/** + * @public + */ +export type Autocomplete = { + path: { + provider: string; + resource: string; + }; + body: AutocompleteRequest; +}; +/** + * @public + */ +export type CancelTask = { + path: { + taskId: string; + }; +}; +/** + * @public + */ +export type DryRun = { + body: DryRunRequest; +}; +/** + * @public + */ +export type GetTask = { + path: { + taskId: string; + }; +}; +/** + * @public + */ +export type GetTemplateParameterSchema = { + path: { + namespace: string; + kind: string; + name: string; + }; +}; +/** + * @public + */ +export type ListActions = {}; +/** + * @public + */ +export type ListTasks = { + query: { + createdBy?: Array<string>; + limit?: number; + offset?: number; + order?: Array<string>; + status?: Array<string>; + }; +}; +/** + * @public + */ +export type ListTemplatingExtensions = {}; +/** + * @public + */ +export type Retry = { + path: { + taskId: string; + }; + body: RetryRequest; +}; +/** + * @public + */ +export type Scaffold = { + body: ScaffolderScaffoldOptions; +}; +/** + * @public + */ +export type StreamLogsPolling = { + path: { + taskId: string; + }; + query: { + after?: number; + }; +}; + +/** + * @public + */ +export class DefaultApiClient { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise<string> }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + /** + * Perform an autocomplete for the given provider and resource. + * @param provider - + * @param resource - + * @param autocompleteRequest - + */ + public async autocomplete( + // @ts-ignore + request: Autocomplete, + options?: RequestOptions, + ): Promise<TypedResponse<Autocomplete200Response>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/autocomplete/{provider}/{resource}`; + + const uri = parser.parse(uriTemplate).expand({ + provider: request.path.provider, + resource: request.path.resource, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Sends a signal to a task broker to cancel the running task by taskId. + * @param taskId - + */ + public async cancelTask( + // @ts-ignore + request: CancelTask, + options?: RequestOptions, + ): Promise<TypedResponse<CancelTask200Response>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks/{taskId}/cancel`; + + const uri = parser.parse(uriTemplate).expand({ + taskId: request.path.taskId, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + }); + } + + /** + * Perform a dry-run of a template + * @param dryRunRequest - + */ + public async dryRun( + // @ts-ignore + request: DryRun, + options?: RequestOptions, + ): Promise<TypedResponse<DryRun200Response>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/dry-run`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Get a task by ID. + * @param taskId - + */ + public async getTask( + // @ts-ignore + request: GetTask, + options?: RequestOptions, + ): Promise<TypedResponse<SerializedTask>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks/{taskId}`; + + const uri = parser.parse(uriTemplate).expand({ + taskId: request.path.taskId, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get template parameter schema. + * @param namespace - + * @param kind - + * @param name - + */ + public async getTemplateParameterSchema( + // @ts-ignore + request: GetTemplateParameterSchema, + options?: RequestOptions, + ): Promise<TypedResponse<TemplateParameterSchema>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/templates/{namespace}/{kind}/{name}/parameter-schema`; + + const uri = parser.parse(uriTemplate).expand({ + namespace: request.path.namespace, + kind: request.path.kind, + name: request.path.name, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Returns a list of all installed actions. + */ + public async listActions( + // @ts-ignore + request: ListActions, + options?: RequestOptions, + ): Promise<TypedResponse<Array<Action>>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/actions`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Returns a list of tasks, filtering by ownership and/or status if given. + * @param createdBy - Created by + * @param limit - Number of records to return in the response. + * @param offset - Number of records to skip in the query page. + * @param order - Order + * @param status - Status + */ + public async listTasks( + // @ts-ignore + request: ListTasks, + options?: RequestOptions, + ): Promise<TypedResponse<ListTasksResponse>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks{?createdBy*,limit,offset,order*,status*}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Returns a structure describing the available templating extensions. + */ + public async listTemplatingExtensions( + // @ts-ignore + request: ListTemplatingExtensions, + options?: RequestOptions, + ): Promise<TypedResponse<ListTemplatingExtensionsResponse>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/templating-extensions`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Starts the task again from the point where it failed. + * @param taskId - + * @param retryRequest - + */ + public async retry( + // @ts-ignore + request: Retry, + options?: RequestOptions, + ): Promise<TypedResponse<Scaffold201Response>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks/{taskId}/retry`; + + const uri = parser.parse(uriTemplate).expand({ + taskId: request.path.taskId, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Executes the scaffolding of a component, given a template and its parameter values. + * @param scaffolderScaffoldOptions - + */ + public async scaffold( + // @ts-ignore + request: Scaffold, + options?: RequestOptions, + ): Promise<TypedResponse<Scaffold201Response>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Get events for a task by ID. + * @param taskId - + * @param after - Offset event ID to stream events after. + */ + public async streamLogsPolling( + // @ts-ignore + request: StreamLogsPolling, + options?: RequestOptions, + ): Promise<TypedResponse<Array<SerializedTaskEvent>>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/v2/tasks/{taskId}/events{?after}`; + + const uri = parser.parse(uriTemplate).expand({ + taskId: request.path.taskId, + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/apis/index.ts b/plugins/scaffolder-common/src/schema/openapi/generated/apis/index.ts new file mode 100644 index 0000000000..fc7c83b736 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/apis/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './Api.client'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/index.ts b/plugins/scaffolder-common/src/schema/openapi/generated/index.ts new file mode 100644 index 0000000000..dc3055033d --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './apis'; +export * from './models'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Action.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Action.model.ts new file mode 100644 index 0000000000..f9c028f3e3 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Action.model.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ActionExample } from '../models/ActionExample.model'; +import { ActionSchema } from '../models/ActionSchema.model'; + +/** + * The response shape for a single action in the `listActions` call to the `scaffolder-backend` + * @public + */ +export interface Action { + id: string; + description?: string; + examples?: Array<ActionExample>; + schema?: ActionSchema; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionExample.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionExample.model.ts new file mode 100644 index 0000000000..50550e2883 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionExample.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A single action example + * @public + */ +export interface ActionExample { + description: string; + example: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionSchema.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionSchema.model.ts new file mode 100644 index 0000000000..35d2014181 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ActionSchema.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ActionSchema { + /** + * A type representing all allowed JSON object values. + */ + input?: { [key: string]: any }; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200Response.model.ts new file mode 100644 index 0000000000..e3eec0aa20 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Autocomplete200ResponseResultsInner } from '../models/Autocomplete200ResponseResultsInner.model'; + +/** + * @public + */ +export interface Autocomplete200Response { + results: Array<Autocomplete200ResponseResultsInner>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts new file mode 100644 index 0000000000..00ccb41b0f --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete200ResponseResultsInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete200ResponseResultsInner { + title?: string; + id: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete400Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete400Response.model.ts new file mode 100644 index 0000000000..1456babb96 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Autocomplete400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete400Response { + message?: string; + name?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/AutocompleteRequest.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/AutocompleteRequest.model.ts new file mode 100644 index 0000000000..769a929918 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/AutocompleteRequest.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface AutocompleteRequest { + context: { [key: string]: string }; + token: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/CancelTask200Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/CancelTask200Response.model.ts new file mode 100644 index 0000000000..f29c509d41 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/CancelTask200Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface CancelTask200Response { + status?: TaskStatus; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200Response.model.ts new file mode 100644 index 0000000000..62e3689d5d --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200Response.model.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRun200ResponseAllOfDirectoryContentsInner } from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +import { DryRun200ResponseAllOfStepsInner } from '../models/DryRun200ResponseAllOfStepsInner.model'; +import { DryRunResultLogInner } from '../models/DryRunResultLogInner.model'; + +/** + * @public + */ +export interface DryRun200Response { + log: Array<DryRunResultLogInner>; + directoryContents: Array<DryRun200ResponseAllOfDirectoryContentsInner>; + /** + * A type representing all allowed JSON object values. + */ + output: { [key: string]: any }; + steps: Array<DryRun200ResponseAllOfStepsInner>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts new file mode 100644 index 0000000000..5b6c2ff9c7 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOf.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRun200ResponseAllOfDirectoryContentsInner } from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +import { DryRun200ResponseAllOfStepsInner } from '../models/DryRun200ResponseAllOfStepsInner.model'; + +/** + * @public + */ +export interface DryRun200ResponseAllOf { + steps: Array<DryRun200ResponseAllOfStepsInner>; + directoryContents?: Array<DryRun200ResponseAllOfDirectoryContentsInner>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts new file mode 100644 index 0000000000..2646ca49f9 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfDirectoryContentsInner.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRun200ResponseAllOfDirectoryContentsInner { + path: string; + executable?: boolean; + base64Content: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts new file mode 100644 index 0000000000..2a462edefa --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRun200ResponseAllOfStepsInner.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRun200ResponseAllOfStepsInner { + [key: string]: any; + + id: string; + name: string; + action: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequest.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequest.model.ts new file mode 100644 index 0000000000..212b36c26b --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequest.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunRequestDirectoryContentsInner } from '../models/DryRunRequestDirectoryContentsInner.model'; + +/** + * @public + */ +export interface DryRunRequest { + template: any; + /** + * A type representing all allowed JSON object values. + */ + values: { [key: string]: any }; + secrets?: { [key: string]: string }; + directoryContents: Array<DryRunRequestDirectoryContentsInner>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts new file mode 100644 index 0000000000..ddcae4fd9d --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunRequestDirectoryContentsInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface DryRunRequestDirectoryContentsInner { + path?: string; + base64Content?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResult.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResult.model.ts new file mode 100644 index 0000000000..6e2ad23ef4 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResult.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInner } from '../models/DryRunResultLogInner.model'; +import { SerializedFile } from '../models/SerializedFile.model'; + +/** + * @public + */ +export interface DryRunResult { + log: Array<DryRunResultLogInner>; + directoryContents: Array<SerializedFile>; + /** + * A type representing all allowed JSON object values. + */ + output: { [key: string]: any }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts new file mode 100644 index 0000000000..4c6b786d82 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInner.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInnerBody } from '../models/DryRunResultLogInnerBody.model'; + +/** + * @public + */ +export interface DryRunResultLogInner { + body: DryRunResultLogInnerBody; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts new file mode 100644 index 0000000000..e3b19be045 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBody.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface DryRunResultLogInnerBody { + message: string; + status?: TaskStatus; + stepId?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts new file mode 100644 index 0000000000..e67240ee54 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/DryRunResultLogInnerBodyAllOf.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * @public + */ +export interface DryRunResultLogInnerBodyAllOf { + message: string; + status?: TaskStatus; + stepId?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorError.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..e0265e95d7 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorError.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorError { + name: string; + message: string; + stack?: string; + code?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorRequest.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..3eb5e15740 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorRequest.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorResponse.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..edbcc32df7 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ErrorResponse.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorResponse { + statusCode: number; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonPrimitive.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonPrimitive.model.ts new file mode 100644 index 0000000000..6aa6394c14 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonPrimitive.model.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A type representing all allowed JSON primitive values. + * @public + */ +export type JsonPrimitive = any | boolean | number | string; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonValue.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonValue.model.ts new file mode 100644 index 0000000000..9fe2ac9de3 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/JsonValue.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { JsonPrimitive } from '../models/JsonPrimitive.model'; + +/** + * A type representing all allowed JSON values. + * @public + */ +export type JsonValue = + | Array<JsonValue> + | JsonPrimitive + | { [key: string]: any }; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTasksResponse.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTasksResponse.model.ts new file mode 100644 index 0000000000..9347c766a9 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTasksResponse.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { SerializedTask } from '../models/SerializedTask.model'; + +/** + * The response shape for the `listTasks` call to the `scaffolder-backend` + * @public + */ +export interface ListTasksResponse { + tasks: Array<SerializedTask>; + totalTasks?: number; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts new file mode 100644 index 0000000000..74b7cd3780 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponse.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ListTemplatingExtensionsResponseGlobals } from '../models/ListTemplatingExtensionsResponseGlobals.model'; +import { TemplateFilter } from '../models/TemplateFilter.model'; + +/** + * The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface ListTemplatingExtensionsResponse { + filters: { [key: string]: TemplateFilter }; + globals: ListTemplatingExtensionsResponseGlobals; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts new file mode 100644 index 0000000000..1f022a0675 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ListTemplatingExtensionsResponseGlobals.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TemplateGlobalFunction } from '../models/TemplateGlobalFunction.model'; +import { TemplateGlobalValue } from '../models/TemplateGlobalValue.model'; + +/** + * @public + */ +export interface ListTemplatingExtensionsResponseGlobals { + functions: { [key: string]: TemplateGlobalFunction }; + values: { [key: string]: TemplateGlobalValue }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ModelError.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..958fde7d0b --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ModelError.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +/** + * @public + */ +export interface ModelError { + [key: string]: any; + + error: ErrorError; + request?: ErrorRequest; + response: ErrorResponse; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/RetryRequest.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/RetryRequest.model.ts new file mode 100644 index 0000000000..858fa67566 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/RetryRequest.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface RetryRequest { + secrets?: { [key: string]: string }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold201Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold201Response.model.ts new file mode 100644 index 0000000000..1271642e81 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold201Response.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Scaffold201Response { + id: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold400Response.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold400Response.model.ts new file mode 100644 index 0000000000..e3cb7eaa45 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/Scaffold400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ValidationError } from '../models/ValidationError.model'; + +/** + * @public + */ +export interface Scaffold400Response { + errors: Array<ValidationError>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts new file mode 100644 index 0000000000..93f4ae71c0 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderScaffoldOptions.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * The input options to the `scaffold` method of the `ScaffolderClient`. + * @public + */ +export interface ScaffolderScaffoldOptions { + templateRef: string; + values: { [key: string]: any }; + secrets?: { [key: string]: string }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts new file mode 100644 index 0000000000..3e0f4ef866 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ScaffolderUsageExample.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * A single scaffolder usage example + * @public + */ +export interface ScaffolderUsageExample { + description?: string; + example: string; + notes?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedFile.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedFile.model.ts new file mode 100644 index 0000000000..65a3c714a7 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedFile.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface SerializedFile { + path: string; + content: string; + executable?: boolean; + symlink?: boolean; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTask.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTask.model.ts new file mode 100644 index 0000000000..67cbf14279 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTask.model.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TaskSecrets } from '../models/TaskSecrets.model'; +import { TaskStatus } from '../models/TaskStatus.model'; + +/** + * SerializedTask + * @public + */ +export interface SerializedTask { + id: string; + spec: any; + status: TaskStatus; + createdAt: string; + lastHeartbeatAt?: string; + createdBy?: string; + secrets?: TaskSecrets; + /** + * A type representing all allowed JSON object values. + */ + state?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts new file mode 100644 index 0000000000..6e4ddaa296 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/SerializedTaskEvent.model.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DryRunResultLogInnerBody } from '../models/DryRunResultLogInnerBody.model'; +import { TaskEventType } from '../models/TaskEventType.model'; + +/** + * SerializedTaskEvent + * @public + */ +export interface SerializedTaskEvent { + id: number; + isTaskRecoverable?: boolean; + taskId: string; + body: DryRunResultLogInnerBody; + type: TaskEventType; + createdAt: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskEventType.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskEventType.model.ts new file mode 100644 index 0000000000..d32d77a448 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskEventType.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type TaskEventType = 'cancelled' | 'completion' | 'log' | 'recovered'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecrets.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecrets.model.ts new file mode 100644 index 0000000000..c78c39c1ec --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecrets.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * TaskSecrets + * @public + */ +export interface TaskSecrets { + backstageToken?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts new file mode 100644 index 0000000000..0b33852cc9 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskSecretsAllOf.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TaskSecretsAllOf { + backstageToken?: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskStatus.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskStatus.model.ts new file mode 100644 index 0000000000..1f209a3656 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TaskStatus.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type TaskStatus = + | 'cancelled' + | 'completed' + | 'failed' + | 'open' + | 'processing' + | 'skipped'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilter.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilter.model.ts new file mode 100644 index 0000000000..7c631978e6 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilter.model.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ScaffolderUsageExample } from '../models/ScaffolderUsageExample.model'; +import { TemplateFilterSchema } from '../models/TemplateFilterSchema.model'; + +/** + * The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateFilter { + description?: string; + schema?: TemplateFilterSchema; + examples?: Array<ScaffolderUsageExample>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts new file mode 100644 index 0000000000..5a95a58ead --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateFilterSchema.model.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateFilterSchema { + /** + * A type representing all allowed JSON object values. + */ + input?: { [key: string]: any }; + arguments?: Array<{ [key: string]: any }>; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts new file mode 100644 index 0000000000..ee19ce723b --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunction.model.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ScaffolderUsageExample } from '../models/ScaffolderUsageExample.model'; +import { TemplateGlobalFunctionSchema } from '../models/TemplateGlobalFunctionSchema.model'; + +/** + * The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateGlobalFunction { + description?: string; + schema?: TemplateGlobalFunctionSchema; + examples?: Array<ScaffolderUsageExample>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts new file mode 100644 index 0000000000..b3a39c3b24 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalFunctionSchema.model.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateGlobalFunctionSchema { + arguments?: Array<{ [key: string]: any }>; + /** + * A type representing all allowed JSON object values. + */ + output?: { [key: string]: any }; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts new file mode 100644 index 0000000000..95d177a05a --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateGlobalValue.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend` + * @public + */ +export interface TemplateGlobalValue { + description?: string; + value: any | null; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts new file mode 100644 index 0000000000..8638ee8114 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchema.model.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { TemplateParameterSchemaStepsInner } from '../models/TemplateParameterSchemaStepsInner.model'; + +/** + * The shape of each entry of parameters which gets rendered as a separate step in the wizard input + * @public + */ +export interface TemplateParameterSchema { + [key: string]: any; + + title: string; + description?: string; + steps: Array<TemplateParameterSchemaStepsInner>; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts new file mode 100644 index 0000000000..2f7892fd41 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface TemplateParameterSchemaStepsInner { + title: string; + description?: string; + schema: any; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationError.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationError.model.ts new file mode 100644 index 0000000000..7e762f616c --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationError.model.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ValidationErrorArgument } from '../models/ValidationErrorArgument.model'; +import { ValidationErrorPathInner } from '../models/ValidationErrorPathInner.model'; + +/** + * @public + */ +export interface ValidationError { + [key: string]: any; + + path: Array<ValidationErrorPathInner>; + property: string; + message: string; + instance: any; + name: string; + argument: ValidationErrorArgument; + stack: string; +} diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts new file mode 100644 index 0000000000..85c9576fd0 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorArgument = any | boolean | number | string; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts new file mode 100644 index 0000000000..4535c735db --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/ValidationErrorPathInner.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorPathInner = number | string; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/models/index.ts b/plugins/scaffolder-common/src/schema/openapi/generated/models/index.ts new file mode 100644 index 0000000000..1bc447fa3d --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/models/index.ts @@ -0,0 +1,65 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from '../models/Action.model'; +export * from '../models/ActionExample.model'; +export * from '../models/ActionSchema.model'; +export * from '../models/Autocomplete200Response.model'; +export * from '../models/Autocomplete200ResponseResultsInner.model'; +export * from '../models/Autocomplete400Response.model'; +export * from '../models/AutocompleteRequest.model'; +export * from '../models/CancelTask200Response.model'; +export * from '../models/DryRun200Response.model'; +export * from '../models/DryRun200ResponseAllOf.model'; +export * from '../models/DryRun200ResponseAllOfDirectoryContentsInner.model'; +export * from '../models/DryRun200ResponseAllOfStepsInner.model'; +export * from '../models/DryRunRequest.model'; +export * from '../models/DryRunRequestDirectoryContentsInner.model'; +export * from '../models/DryRunResult.model'; +export * from '../models/DryRunResultLogInner.model'; +export * from '../models/DryRunResultLogInnerBody.model'; +export * from '../models/DryRunResultLogInnerBodyAllOf.model'; +export * from '../models/ErrorError.model'; +export * from '../models/ErrorRequest.model'; +export * from '../models/ErrorResponse.model'; +export * from '../models/JsonPrimitive.model'; +export * from '../models/JsonValue.model'; +export * from '../models/ListTasksResponse.model'; +export * from '../models/ListTemplatingExtensionsResponse.model'; +export * from '../models/ListTemplatingExtensionsResponseGlobals.model'; +export * from '../models/ModelError.model'; +export * from '../models/RetryRequest.model'; +export * from '../models/Scaffold201Response.model'; +export * from '../models/Scaffold400Response.model'; +export * from '../models/ScaffolderScaffoldOptions.model'; +export * from '../models/ScaffolderUsageExample.model'; +export * from '../models/SerializedFile.model'; +export * from '../models/SerializedTask.model'; +export * from '../models/SerializedTaskEvent.model'; +export * from '../models/TaskEventType.model'; +export * from '../models/TaskSecrets.model'; +export * from '../models/TaskSecretsAllOf.model'; +export * from '../models/TaskStatus.model'; +export * from '../models/TemplateFilter.model'; +export * from '../models/TemplateFilterSchema.model'; +export * from '../models/TemplateGlobalFunction.model'; +export * from '../models/TemplateGlobalFunctionSchema.model'; +export * from '../models/TemplateGlobalValue.model'; +export * from '../models/TemplateParameterSchema.model'; +export * from '../models/TemplateParameterSchemaStepsInner.model'; +export * from '../models/ValidationError.model'; +export * from '../models/ValidationErrorArgument.model'; +export * from '../models/ValidationErrorPathInner.model'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/pluginId.ts b/plugins/scaffolder-common/src/schema/openapi/generated/pluginId.ts new file mode 100644 index 0000000000..b898028be5 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/pluginId.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const pluginId = 'scaffolder'; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/types/discovery.ts b/plugins/scaffolder-common/src/schema/openapi/generated/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise<string>; +}; diff --git a/plugins/scaffolder-common/src/schema/openapi/generated/types/fetch.ts b/plugins/scaffolder-common/src/schema/openapi/generated/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/generated/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/plugins/scaffolder-common/src/schema/openapi/index.ts b/plugins/scaffolder-common/src/schema/openapi/index.ts new file mode 100644 index 0000000000..196aad553a --- /dev/null +++ b/plugins/scaffolder-common/src/schema/openapi/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './generated'; diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index bf20a8b4af..99650afc63 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.3.2-next.0 + +### Patch Changes + +- 812485c: Add step info to scaffolder action context to access the step id and name. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.11.0-next.0 + - @backstage/backend-test-utils@1.7.1-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/types@1.2.1 + +## 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..166228cb61 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.2-next.0", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts b/plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts index a6703a12d1..6d2fa4f4d5 100644 --- a/plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts +++ b/plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts @@ -22,6 +22,7 @@ import { } from '@backstage/backend-test-utils'; import { JsonObject, JsonValue } from '@backstage/types'; import { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { CheckpointContext } from '@backstage/plugin-scaffolder-node/alpha'; import { loggerToWinstonLogger } from './loggerToWinstonLogger'; /** @@ -44,16 +45,19 @@ export function createMockActionContext< output: jest.fn(), createTemporaryDirectory: jest.fn(), input: {} as TActionInput, - async checkpoint<T extends JsonValue | void>(opts: { - key: string; - fn: () => Promise<T> | T; - }): Promise<T> { + async checkpoint<T extends JsonValue | void>( + opts: CheckpointContext<T>, + ): Promise<T> { return opts.fn(); }, getInitiatorCredentials: () => Promise.resolve(credentials), task: { id: 'mock-task-id', }, + step: { + id: 'mock-step-id', + name: 'mock step name', + }, }; const createDefaultWorkspace = () => ({ diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 5ed6355c8c..c7b2c8a5c7 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,81 @@ # @backstage/plugin-scaffolder-node +## 0.11.0-next.0 + +### Minor Changes + +- c08cbc4: Move Scaffolder API to OpenAPI + +### Patch Changes + +- 812485c: Add step info to scaffolder action context to access the step id and name. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.1 + +## 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..453abaaa82 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.11.0-next.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-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index a96f312d2d..09541fbc56 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -27,6 +27,31 @@ export type AutocompleteHandler = ({ }[]; }>; +// @alpha +export type CheckpointContext<T extends JsonValue | void = JsonValue> = { + key: string; + fn: () => Promise<T> | T; +}; + +// @alpha +export type CheckpointState = { + [key: string]: CheckpointStateValue; +}; + +// @alpha +export type CheckpointStateValue<T extends JsonValue = JsonValue> = + | { + status: 'failed'; + reason: string; + } + | { + status: 'success'; + value: T; + }; + +// @alpha +export type CheckpointStatus = 'failed' | 'success'; + // @alpha (undocumented) export type CreatedTemplateFilter< TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], @@ -187,6 +212,11 @@ export type TemplateGlobalFunctionExample = { notes?: string; }; +// @alpha +export type UpdateTaskCheckpointOptions = { + key: string; +} & CheckpointStateValue; + // @alpha export interface WorkspaceProvider { // (undocumented) diff --git a/plugins/scaffolder-node/report.api.md b/plugins/scaffolder-node/report.api.md index a23a9137b1..c97344867a 100644 --- a/plugins/scaffolder-node/report.api.md +++ b/plugins/scaffolder-node/report.api.md @@ -4,17 +4,20 @@ ```ts import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { CheckpointContext } from '@backstage/plugin-scaffolder-node/alpha'; import { Expand } from '@backstage/types'; 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'; import { SpawnOptionsWithoutStdio } from 'child_process'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TemplateInfo } from '@backstage/plugin-scaffolder-common'; +import { UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node/alpha'; import { UrlReaderService } from '@backstage/backend-plugin-api'; import { UserEntity } from '@backstage/catalog-model'; import { Writable } from 'stream'; @@ -30,10 +33,9 @@ export type ActionContext< secrets?: TaskSecrets; workspacePath: string; input: TActionInput; - checkpoint<T extends JsonValue | void>(opts: { - key: string; - fn: () => Promise<T> | T; - }): Promise<T>; + checkpoint<T extends JsonValue | void>( + opts: CheckpointContext<T>, + ): Promise<T>; output( name: keyof TActionOutput, value: TActionOutput[keyof TActionOutput], @@ -51,6 +53,10 @@ export type ActionContext< }; signal?: AbortSignal; each?: JsonObject; + step?: { + id?: string; + name?: string; + }; }; // @public (undocumented) @@ -338,7 +344,11 @@ export type SerializedTaskEvent = { id: number; isTaskRecoverable?: boolean; taskId: string; - body: JsonObject; + body: { + message: string; + stepId?: string; + status?: TaskStatus; + } & JsonObject; type: TaskEventType; createdAt: string; }; @@ -373,6 +383,7 @@ export interface TaskBroker { order: 'asc' | 'desc'; field: string; }[]; + permissionFilters?: PermissionCriteria<TaskFilters>; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number; @@ -446,24 +457,31 @@ export interface TaskContext { // (undocumented) taskId?: string; // (undocumented) - updateCheckpoint?( - options: - | { - key: string; - status: 'success'; - value: JsonValue; - } - | { - key: string; - status: 'failed'; - reason: string; - }, - ): Promise<void>; + updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>; } // @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; @@ -475,7 +493,8 @@ export type TaskStatus = | 'completed' | 'failed' | 'open' - | 'processing'; + | 'processing' + | 'skipped'; // @public (undocumented) export type TemplateAction< diff --git a/plugins/scaffolder-node/src/actions/types.ts b/plugins/scaffolder-node/src/actions/types.ts index f13d256332..04b1e77a7a 100644 --- a/plugins/scaffolder-node/src/actions/types.ts +++ b/plugins/scaffolder-node/src/actions/types.ts @@ -23,6 +23,8 @@ import { BackstageCredentials, LoggerService, } from '@backstage/backend-plugin-api'; +import { CheckpointContext } from '@backstage/plugin-scaffolder-node/alpha'; + /** * ActionContext is passed into scaffolder actions. * @public @@ -36,10 +38,9 @@ export type ActionContext< secrets?: TaskSecrets; workspacePath: string; input: TActionInput; - checkpoint<T extends JsonValue | void>(opts: { - key: string; - fn: () => Promise<T> | T; - }): Promise<T>; + checkpoint<T extends JsonValue | void>( + opts: CheckpointContext<T>, + ): Promise<T>; output( name: keyof TActionOutput, value: TActionOutput[keyof TActionOutput], @@ -92,6 +93,20 @@ export type ActionContext< * Optional value of each invocation */ each?: JsonObject; + + /** + * Step information + */ + step?: { + /** + * The id of step which triggered the action + */ + id?: string; + /** + * The name of the step which triggered the action + */ + name?: string; + }; }; /** @public */ diff --git a/plugins/scaffolder-node/src/alpha/checkpoints/index.ts b/plugins/scaffolder-node/src/alpha/checkpoints/index.ts new file mode 100644 index 0000000000..16c936b235 --- /dev/null +++ b/plugins/scaffolder-node/src/alpha/checkpoints/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './types'; diff --git a/plugins/scaffolder-node/src/alpha/checkpoints/types.ts b/plugins/scaffolder-node/src/alpha/checkpoints/types.ts new file mode 100644 index 0000000000..5bd1eb5cd3 --- /dev/null +++ b/plugins/scaffolder-node/src/alpha/checkpoints/types.ts @@ -0,0 +1,57 @@ +/* + * 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 { JsonValue } from '@backstage/types'; + +/** + * The status of a checkpoint, indicating whether it succeeded or failed. + * + * @alpha + */ +export type CheckpointStatus = 'failed' | 'success'; + +/** + * Represents the union of all possible checkpoint state values. + * + * @alpha + */ +export type CheckpointStateValue<T extends JsonValue = JsonValue> = + | { status: 'failed'; reason: string } + | { status: 'success'; value: T }; + +/** + * A map of checkpoint keys to their states. + * + * @alpha + */ +export type CheckpointState = { + [key: string]: CheckpointStateValue; +}; + +/** + * Context for checkpoint function invocation. + * + * @alpha + */ +export type CheckpointContext<T extends JsonValue | void = JsonValue> = { + /** + * Unique key for the checkpoint + */ + key: string; + /** + * Function to execute for the checkpoint + */ + fn: () => Promise<T> | T; +}; diff --git a/plugins/scaffolder-node/src/alpha/index.ts b/plugins/scaffolder-node/src/alpha/index.ts index 9df968a52d..30f95f116a 100644 --- a/plugins/scaffolder-node/src/alpha/index.ts +++ b/plugins/scaffolder-node/src/alpha/index.ts @@ -28,6 +28,7 @@ export * from '../tasks/alpha'; export * from './filters'; export * from './globals'; export * from './types'; +export * from './checkpoints'; /** * Extension point for managing scaffolder actions. diff --git a/plugins/scaffolder-node/src/tasks/alpha.ts b/plugins/scaffolder-node/src/tasks/alpha.ts index fb6b09026c..4354a798cf 100644 --- a/plugins/scaffolder-node/src/tasks/alpha.ts +++ b/plugins/scaffolder-node/src/tasks/alpha.ts @@ -1,3 +1,5 @@ +import { CheckpointStateValue } from '../alpha'; + /* * Copyright 2024 The Backstage Authors * @@ -14,3 +16,12 @@ * limitations under the License. */ export * from './serializer'; + +/** + * Options for updating a checkpoint in a task. + * + * @alpha + */ +export type UpdateTaskCheckpointOptions = { + key: string; +} & CheckpointStateValue; 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 d8cfd24530..aaac468fce 100644 --- a/plugins/scaffolder-node/src/tasks/types.ts +++ b/plugins/scaffolder-node/src/tasks/types.ts @@ -15,8 +15,10 @@ */ import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; -import { JsonObject, JsonValue, Observable } from '@backstage/types'; +import { JsonObject, Observable } from '@backstage/types'; +import { UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node/alpha'; /** * TaskSecrets @@ -37,7 +39,8 @@ export type TaskStatus = | 'completed' | 'failed' | 'open' - | 'processing'; + | 'processing' + | 'skipped'; /** * The state of a completed task. @@ -78,7 +81,11 @@ export type SerializedTaskEvent = { id: number; isTaskRecoverable?: boolean; taskId: string; - body: JsonObject; + body: { + message: string; + stepId?: string; + status?: TaskStatus; + } & JsonObject; type: TaskEventType; createdAt: string; }; @@ -104,6 +111,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 * @@ -129,19 +155,7 @@ export interface TaskContext { | undefined >; - updateCheckpoint?( - options: - | { - key: string; - status: 'success'; - value: JsonValue; - } - | { - key: string; - status: 'failed'; - reason: string; - }, - ): Promise<void>; + updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>; serializeWorkspace?(options: { path: string }): Promise<void>; @@ -194,6 +208,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..a30f8d371d 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,117 @@ # @backstage/plugin-scaffolder-react +## 1.19.0-next.1 + +### Minor Changes + +- 4f99e10: **DEPRECATION**: The following types have been deprecated from this package and moved into `@backstage/plugin-scaffolder-common` and should be imported from there instead. + + `Action`, `ListActionsResponse`, `LogEvent`, `ScaffolderApi`, `ScaffolderDryRunOptions`, `ScaffolderDryRunResponse`, `ScaffolderGetIntegrationsListOptions`, `ScaffolderGetIntegrationsListResponse`, + `ScaffolderOutputLink`, `ScaffolderOutputText`, `ScaffolderScaffoldOptions`, `ScaffolderScaffoldResponse`, `ScaffolderStreamLogsOptions`, `ScaffolderTask`, `ScaffolderTaskOutput`, `ScaffolderTaskStatus`, + `ScaffolderUsageExample`, `TemplateFilter`, `TemplateGlobalFunction`, `TemplateGlobalValue`, `TemplateParameterSchema`. + +- c08cbc4: Move Scaffolder API to OpenAPI + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- c4b7c50: Export `FormField` type from `/alpha` in `-react` package, and internal refactor. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.36 + +## 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..c8706c790a 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.19.0-next.1", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index 2014bff9be..504d173267 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -5,6 +5,7 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; @@ -12,13 +13,13 @@ import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; import { Dispatch } from 'react'; import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FieldSchema } from '@backstage/plugin-scaffolder-react'; import { FieldValidation } from '@rjsf/utils'; -import { FormField } from '@internal/scaffolder'; import { FormProps } from '@backstage/plugin-scaffolder-react'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; @@ -155,6 +156,12 @@ export const FormDecoratorBlueprint: ExtensionBlueprint<{ }; }>; +// @alpha (undocumented) +export interface FormField { + // (undocumented) + readonly $$type: '@backstage/scaffolder/FormField'; +} + // @alpha export const FormFieldBlueprint: ExtensionBlueprint<{ kind: 'scaffolder-form-field'; @@ -218,9 +225,13 @@ export const formFieldsApi: ExtensionDefinition<{ }; kind: 'api'; name: 'form-fields'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; // @alpha @deprecated (undocumented) diff --git a/plugins/scaffolder-react/report.api.md b/plugins/scaffolder-react/report.api.md index d66ec36acb..4b81a18eb6 100644 --- a/plugins/scaffolder-react/report.api.md +++ b/plugins/scaffolder-react/report.api.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Action as Action_2 } from '@backstage/plugin-scaffolder-common'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; @@ -23,9 +24,10 @@ import { IChangeEvent } from '@rjsf/core'; import { IdSchema } from '@rjsf/utils'; import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; -import { JsonValue } from '@backstage/types'; import { JSX as JSX_2 } from 'react/jsx-runtime'; -import { Observable } from '@backstage/types'; +import { ListActionsResponse as ListActionsResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ListTemplatingExtensionsResponse as ListTemplatingExtensionsResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { LogEvent as LogEvent_2 } from '@backstage/plugin-scaffolder-common'; import { PropsWithChildren } from 'react'; import { ReactNode } from 'react'; import { Ref } from 'react'; @@ -33,27 +35,34 @@ import { Registry } from '@rjsf/utils'; import { RegistryWidgetsType } from '@rjsf/utils'; import { RJSFSchema } from '@rjsf/utils'; import { RJSFValidationError } from '@rjsf/utils'; +import { ScaffolderApi as ScaffolderApi_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderDryRunOptions as ScaffolderDryRunOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderDryRunResponse as ScaffolderDryRunResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderGetIntegrationsListOptions as ScaffolderGetIntegrationsListOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderGetIntegrationsListResponse as ScaffolderGetIntegrationsListResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderOutputLink as ScaffolderOutputLink_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderOutputText as ScaffolderOutputText_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderScaffoldOptions as ScaffolderScaffoldOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderScaffoldResponse as ScaffolderScaffoldResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderStreamLogsOptions as ScaffolderStreamLogsOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderTask as ScaffolderTask_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderTaskOutput as ScaffolderTaskOutput_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderTaskStatus as ScaffolderTaskStatus_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderUsageExample as ScaffolderUsageExample_2 } from '@backstage/plugin-scaffolder-common'; import { StrictRJSFSchema } from '@rjsf/utils'; -import { TaskSpec } from '@backstage/plugin-scaffolder-common'; -import { TaskStep } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateFilter as TemplateFilter_2 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGlobalFunction as TemplateGlobalFunction_2 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGlobalValue as TemplateGlobalValue_2 } from '@backstage/plugin-scaffolder-common'; +import { TemplateParameterSchema as TemplateParameterSchema_2 } from '@backstage/plugin-scaffolder-common'; import { TemplatesType } from '@rjsf/utils'; import { UIOptionsType } from '@rjsf/utils'; import { UiSchema } from '@rjsf/utils'; import { ValidatorType } from '@rjsf/utils'; import { z } from 'zod'; -// @public -export type Action = { - id: string; - description?: string; - schema?: { - input?: JSONSchema7; - output?: JSONSchema7; - }; - examples?: ActionExample[]; -}; +// @public @deprecated +export type Action = Action_2; // @public @deprecated export type ActionExample = ScaffolderUsageExample; @@ -162,30 +171,15 @@ export type LayoutTemplate<T = any> = NonNullable< FormProps_2<T>['uiSchema'] >['ui:ObjectFieldTemplate']; -// @public -export type ListActionsResponse = Array<Action>; +// @public @deprecated +export type ListActionsResponse = ListActionsResponse_2; -// @public -export type ListTemplatingExtensionsResponse = { - filters: Record<string, TemplateFilter>; - globals: { - functions: Record<string, TemplateGlobalFunction>; - values: Record<string, TemplateGlobalValue>; - }; -}; +// @public @deprecated +export type ListTemplatingExtensionsResponse = + ListTemplatingExtensionsResponse_2; -// @public -export type LogEvent = { - type: 'log' | 'completion' | 'cancelled' | 'recovered'; - body: { - message: string; - stepId?: string; - status?: ScaffolderTaskStatus; - }; - createdAt: string; - id: string; - taskId: string; -}; +// @public @deprecated +export type LogEvent = LogEvent_2; // @public (undocumented) export function makeFieldSchema< @@ -210,125 +204,39 @@ export type ReviewStepProps = { }[]; }; -// @public -export interface ScaffolderApi { - // (undocumented) - autocomplete?(options: { - token: string; - provider: string; - resource: string; - context?: Record<string, string>; - }): Promise<{ - results: { - title?: string; - id: string; - }[]; - }>; - cancelTask(taskId: string): Promise<void>; - // (undocumented) - dryRun?(options: ScaffolderDryRunOptions): Promise<ScaffolderDryRunResponse>; - // (undocumented) - getIntegrationsList( - options: ScaffolderGetIntegrationsListOptions, - ): Promise<ScaffolderGetIntegrationsListResponse>; - // (undocumented) - getTask(taskId: string): Promise<ScaffolderTask>; - // (undocumented) - getTemplateParameterSchema( - templateRef: string, - ): Promise<TemplateParameterSchema>; - listActions(): Promise<ListActionsResponse>; - // (undocumented) - listTasks?(options: { - filterByOwnership: 'owned' | 'all'; - limit?: number; - offset?: number; - }): Promise<{ - tasks: ScaffolderTask[]; - totalTasks?: number; - }>; - listTemplatingExtensions?(): Promise<ListTemplatingExtensionsResponse>; - retry?(taskId: string): Promise<void>; - scaffold( - options: ScaffolderScaffoldOptions, - ): Promise<ScaffolderScaffoldResponse>; - // (undocumented) - streamLogs(options: ScaffolderStreamLogsOptions): Observable<LogEvent>; -} +// @public @deprecated +export type ScaffolderApi = ScaffolderApi_2; // @public (undocumented) -export const scaffolderApiRef: ApiRef<ScaffolderApi>; +export const scaffolderApiRef: ApiRef<ScaffolderApi_2>; -// @public (undocumented) -export interface ScaffolderDryRunOptions { - // (undocumented) - directoryContents: { - path: string; - base64Content: string; - }[]; - // (undocumented) - secrets?: Record<string, string>; - // (undocumented) - template: JsonValue; - // (undocumented) - values: JsonObject; -} +// @public @deprecated (undocumented) +export type ScaffolderDryRunOptions = ScaffolderDryRunOptions_2; -// @public (undocumented) -export interface ScaffolderDryRunResponse { - // (undocumented) - directoryContents: Array<{ - path: string; - base64Content: string; - executable: boolean; - }>; - // (undocumented) - log: Array<Pick<LogEvent, 'body'>>; - // (undocumented) - output: ScaffolderTaskOutput; - // (undocumented) - steps: TaskStep[]; -} +// @public @deprecated (undocumented) +export type ScaffolderDryRunResponse = ScaffolderDryRunResponse_2; // @public export const ScaffolderFieldExtensions: React.ComponentType< React.PropsWithChildren<{}> >; -// @public -export interface ScaffolderGetIntegrationsListOptions { - // (undocumented) - allowedHosts: string[]; -} +// @public @deprecated +export type ScaffolderGetIntegrationsListOptions = + ScaffolderGetIntegrationsListOptions_2; -// @public -export interface ScaffolderGetIntegrationsListResponse { - // (undocumented) - integrations: { - type: string; - title: string; - host: string; - }[]; -} +// @public @deprecated +export type ScaffolderGetIntegrationsListResponse = + ScaffolderGetIntegrationsListResponse_2; // @public export const ScaffolderLayouts: ComponentType<PropsWithChildren<{}>>; -// @public (undocumented) -export type ScaffolderOutputLink = { - title?: string; - icon?: string; - url?: string; - entityRef?: string; -}; +// @public @deprecated (undocumented) +export type ScaffolderOutputLink = ScaffolderOutputLink_2; -// @public (undocumented) -export type ScaffolderOutputText = { - title?: string; - icon?: string; - content?: string; - default?: boolean; -}; +// @public @deprecated (undocumented) +export type ScaffolderOutputText = ScaffolderOutputText_2; // @public export type ScaffolderRJSFField< @@ -437,21 +345,11 @@ export type ScaffolderRJSFRegistryFieldsType< [name: string]: ScaffolderRJSFField<T, S, F>; }; -// @public -export interface ScaffolderScaffoldOptions { - // (undocumented) - secrets?: Record<string, string>; - // (undocumented) - templateRef: string; - // (undocumented) - values: Record<string, JsonValue>; -} +// @public @deprecated +export type ScaffolderScaffoldOptions = ScaffolderScaffoldOptions_2; -// @public -export interface ScaffolderScaffoldResponse { - // (undocumented) - taskId: string; -} +// @public @deprecated +export type ScaffolderScaffoldResponse = ScaffolderScaffoldResponse_2; // @public export type ScaffolderStep = { @@ -461,48 +359,20 @@ export type ScaffolderStep = { startedAt?: string; }; -// @public -export interface ScaffolderStreamLogsOptions { - // (undocumented) - after?: number; - // (undocumented) - isTaskRecoverable?: boolean; - // (undocumented) - taskId: string; -} +// @public @deprecated +export type ScaffolderStreamLogsOptions = ScaffolderStreamLogsOptions_2; -// @public -export type ScaffolderTask = { - id: string; - spec: TaskSpec; - status: 'failed' | 'completed' | 'processing' | 'open' | 'cancelled'; - lastHeartbeatAt: string; - createdAt: string; -}; +// @public @deprecated +export type ScaffolderTask = ScaffolderTask_2; -// @public (undocumented) -export type ScaffolderTaskOutput = { - links?: ScaffolderOutputLink[]; - text?: ScaffolderOutputText[]; -} & { - [key: string]: unknown; -}; +// @public @deprecated (undocumented) +export type ScaffolderTaskOutput = ScaffolderTaskOutput_2; -// @public -export type ScaffolderTaskStatus = - | 'cancelled' - | 'completed' - | 'failed' - | 'open' - | 'processing' - | 'skipped'; +// @public @deprecated +export type ScaffolderTaskStatus = ScaffolderTaskStatus_2; -// @public -export type ScaffolderUsageExample = { - description?: string; - example: string; - notes?: string; -}; +// @public @deprecated +export type ScaffolderUsageExample = ScaffolderUsageExample_2; // @public export interface ScaffolderUseTemplateSecrets { @@ -535,32 +405,14 @@ export type TaskStream = { output?: ScaffolderTaskOutput; }; -// @public -export type TemplateFilter = { - description?: string; - schema?: { - input?: JSONSchema7; - arguments?: JSONSchema7[]; - output?: JSONSchema7; - }; - examples?: ScaffolderUsageExample[]; -}; +// @public @deprecated +export type TemplateFilter = TemplateFilter_2; -// @public -export type TemplateGlobalFunction = { - description?: string; - schema?: { - arguments?: JSONSchema7[]; - output?: JSONSchema7; - }; - examples?: ScaffolderUsageExample[]; -}; +// @public @deprecated +export type TemplateGlobalFunction = TemplateGlobalFunction_2; -// @public -export type TemplateGlobalValue = { - description?: string; - value: JsonValue; -}; +// @public @deprecated +export type TemplateGlobalValue = TemplateGlobalValue_2; // @public (undocumented) export type TemplateGroupFilter = { @@ -568,21 +420,8 @@ export type TemplateGroupFilter = { filter: (entity: TemplateEntityV1beta3) => boolean; }; -// @public -export type TemplateParameterSchema = { - title: string; - description?: string; - presentation?: TemplatePresentationV1beta3; - steps: Array<{ - title: string; - description?: string; - schema: JsonObject; - }>; - EXPERIMENTAL_formDecorators?: { - id: string; - input?: JsonObject; - }[]; -}; +// @public @deprecated +export type TemplateParameterSchema = TemplateParameterSchema_2; // @public export const useCustomFieldExtensions: < diff --git a/plugins/scaffolder-react/src/api/types.ts b/plugins/scaffolder-react/src/api/types.ts index d4a9bbe0f8..b3cb177128 100644 --- a/plugins/scaffolder-react/src/api/types.ts +++ b/plugins/scaffolder-react/src/api/types.ts @@ -13,47 +13,54 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TaskSpec, TaskStep } from '@backstage/plugin-scaffolder-common'; -import { JsonObject, JsonValue, Observable } from '@backstage/types'; -import { JSONSchema7 } from 'json-schema'; -import { TemplateParameterSchema } from '../types'; + +import { + type ScaffolderApi as _ScaffolderApi, + type ScaffolderDryRunOptions as _ScaffolderDryRunOptions, + type ScaffolderDryRunResponse as _ScaffolderDryRunResponse, + type ScaffolderGetIntegrationsListOptions as _ScaffolderGetIntegrationsListOptions, + type ScaffolderGetIntegrationsListResponse as _ScaffolderGetIntegrationsListResponse, + type ScaffolderScaffoldOptions as _ScaffolderScaffoldOptions, + type ScaffolderScaffoldResponse as _ScaffolderScaffoldResponse, + type ScaffolderStreamLogsOptions as _ScaffolderStreamLogsOptions, + type ScaffolderUsageExample as _ScaffolderUsageExample, + type Action as _Action, + type ListActionsResponse as _ListActionsResponse, + type ListTemplatingExtensionsResponse as _ListTemplatingExtensionsResponse, + type LogEvent as _LogEvent, + type ScaffolderOutputLink as _ScaffolderOutputLink, + type ScaffolderOutputText as _ScaffolderOutputText, + type ScaffolderTask as _ScaffolderTask, + type ScaffolderTaskOutput as _ScaffolderTaskOutput, + type ScaffolderTaskStatus as _ScaffolderTaskStatus, + type TemplateFilter as _TemplateFilter, + type TemplateGlobalFunction as _TemplateGlobalFunction, + type TemplateGlobalValue as _TemplateGlobalValue, +} from '@backstage/plugin-scaffolder-common'; /** * The status of each task in a Scaffolder Job * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTaskStatus} instead as this has now been moved. */ -export type ScaffolderTaskStatus = - | 'cancelled' - | 'completed' - | 'failed' - | 'open' - | 'processing' - | 'skipped'; +export type ScaffolderTaskStatus = _ScaffolderTaskStatus; /** * The shape of each task returned from the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTask} instead as this has now been moved. */ -export type ScaffolderTask = { - id: string; - spec: TaskSpec; - status: 'failed' | 'completed' | 'processing' | 'open' | 'cancelled'; - lastHeartbeatAt: string; - createdAt: string; -}; +export type ScaffolderTask = _ScaffolderTask; /** * A single scaffolder usage example * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderUsageExample} instead as this has now been moved. */ -export type ScaffolderUsageExample = { - description?: string; - example: string; - notes?: string; -}; +export type ScaffolderUsageExample = _ScaffolderUsageExample; /** * A single action example @@ -67,249 +74,135 @@ export type ActionExample = ScaffolderUsageExample; * The response shape for a single action in the `listActions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#Action} instead as this has now been moved. */ -export type Action = { - id: string; - description?: string; - schema?: { - input?: JSONSchema7; - output?: JSONSchema7; - }; - examples?: ActionExample[]; -}; +export type Action = _Action; /** * The response shape for the `listActions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ListActionsResponse} instead as this has now been moved. */ -export type ListActionsResponse = Array<Action>; +export type ListActionsResponse = _ListActionsResponse; /** * The response shape for a single filter in the `listTemplatingExtensions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#TemplateFilter} instead as this has now been moved. */ -export type TemplateFilter = { - description?: string; - schema?: { - input?: JSONSchema7; - arguments?: JSONSchema7[]; - output?: JSONSchema7; - }; - examples?: ScaffolderUsageExample[]; -}; +export type TemplateFilter = _TemplateFilter; /** * The response shape for a single global function in the `listTemplatingExtensions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#TemplateGlobalFunction} instead as this has now been moved. */ -export type TemplateGlobalFunction = { - description?: string; - schema?: { - arguments?: JSONSchema7[]; - output?: JSONSchema7; - }; - examples?: ScaffolderUsageExample[]; -}; +export type TemplateGlobalFunction = _TemplateGlobalFunction; /** * The response shape for a single global value in the `listTemplatingExtensions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#TemplateGlobalValue} instead as this has now been moved. */ -export type TemplateGlobalValue = { - description?: string; - value: JsonValue; -}; +export type TemplateGlobalValue = _TemplateGlobalValue; /** * The response shape for the `listTemplatingExtensions` call to the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ListTemplatingExtensionsResponse} instead as this has now been moved. */ -export type ListTemplatingExtensionsResponse = { - filters: Record<string, TemplateFilter>; - globals: { - functions: Record<string, TemplateGlobalFunction>; - values: Record<string, TemplateGlobalValue>; - }; -}; +export type ListTemplatingExtensionsResponse = + _ListTemplatingExtensionsResponse; -/** @public */ -export type ScaffolderOutputLink = { - title?: string; - icon?: string; - url?: string; - entityRef?: string; -}; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderOutputLink} instead as this has now been moved. + */ +export type ScaffolderOutputLink = _ScaffolderOutputLink; -/** @public */ -export type ScaffolderOutputText = { - title?: string; - icon?: string; - content?: string; - default?: boolean; -}; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderOutputText} instead as this has now been moved. + */ +export type ScaffolderOutputText = _ScaffolderOutputText; -/** @public */ -export type ScaffolderTaskOutput = { - links?: ScaffolderOutputLink[]; - text?: ScaffolderOutputText[]; -} & { - [key: string]: unknown; -}; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTaskOutput} instead as this has now been moved. + */ +export type ScaffolderTaskOutput = _ScaffolderTaskOutput; /** * The shape of a `LogEvent` message from the `scaffolder-backend` * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#LogEvent} instead as this has now been moved. */ -export type LogEvent = { - type: 'log' | 'completion' | 'cancelled' | 'recovered'; - body: { - message: string; - stepId?: string; - status?: ScaffolderTaskStatus; - }; - createdAt: string; - id: string; - taskId: string; -}; +export type LogEvent = _LogEvent; /** * The input options to the `scaffold` method of the `ScaffolderClient`. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderScaffoldOptions} instead as this has now been moved. */ -export interface ScaffolderScaffoldOptions { - templateRef: string; - values: Record<string, JsonValue>; - secrets?: Record<string, string>; -} +export type ScaffolderScaffoldOptions = _ScaffolderScaffoldOptions; /** * The response shape of the `scaffold` method of the `ScaffolderClient`. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderScaffoldResponse} instead as this has now been moved. */ -export interface ScaffolderScaffoldResponse { - taskId: string; -} +export type ScaffolderScaffoldResponse = _ScaffolderScaffoldResponse; /** * The arguments for `getIntegrationsList`. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderGetIntegrationsListOptions} instead as this has now been moved. */ -export interface ScaffolderGetIntegrationsListOptions { - allowedHosts: string[]; -} +export type ScaffolderGetIntegrationsListOptions = + _ScaffolderGetIntegrationsListOptions; /** * The response shape for `getIntegrationsList`. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderGetIntegrationsListResponse} instead as this has now been moved. */ -export interface ScaffolderGetIntegrationsListResponse { - integrations: { type: string; title: string; host: string }[]; -} +export type ScaffolderGetIntegrationsListResponse = + _ScaffolderGetIntegrationsListResponse; /** * The input options to the `streamLogs` method of the `ScaffolderClient`. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderStreamLogsOptions} instead as this has now been moved. */ -export interface ScaffolderStreamLogsOptions { - isTaskRecoverable?: boolean; - taskId: string; - after?: number; -} +export type ScaffolderStreamLogsOptions = _ScaffolderStreamLogsOptions; -/** @public */ -export interface ScaffolderDryRunOptions { - template: JsonValue; - values: JsonObject; - secrets?: Record<string, string>; - directoryContents: { path: string; base64Content: string }[]; -} +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderDryRunOptions} instead as this has now been moved. + */ +export type ScaffolderDryRunOptions = _ScaffolderDryRunOptions; + +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderDryRunResponse} instead as this has now been moved. + */ +export type ScaffolderDryRunResponse = _ScaffolderDryRunResponse; -/** @public */ -export interface ScaffolderDryRunResponse { - directoryContents: Array<{ - path: string; - base64Content: string; - executable: boolean; - }>; - log: Array<Pick<LogEvent, 'body'>>; - steps: TaskStep[]; - output: ScaffolderTaskOutput; -} /** * An API to interact with the scaffolder backend. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderApi} instead as this has now been moved. */ -export interface ScaffolderApi { - getTemplateParameterSchema( - templateRef: string, - ): Promise<TemplateParameterSchema>; - - /** - * Executes the scaffolding of a component, given a template and its - * parameter values. - * - * @param options - The {@link ScaffolderScaffoldOptions} the scaffolding. - */ - scaffold( - options: ScaffolderScaffoldOptions, - ): Promise<ScaffolderScaffoldResponse>; - - getTask(taskId: string): Promise<ScaffolderTask>; - - /** - * Sends a signal to a task broker to cancel the running task by taskId. - * - * @param taskId - the id of the task - */ - cancelTask(taskId: string): Promise<void>; - - /** - * Starts the task again from the point where it failed. - * - * @param taskId - the id of the task - */ - retry?(taskId: string): Promise<void>; - - listTasks?(options: { - filterByOwnership: 'owned' | 'all'; - limit?: number; - offset?: number; - }): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }>; - - getIntegrationsList( - options: ScaffolderGetIntegrationsListOptions, - ): Promise<ScaffolderGetIntegrationsListResponse>; - - /** - * Returns a list of all installed actions. - */ - listActions(): Promise<ListActionsResponse>; - - /** - * Returns a structure describing the available templating extensions. - */ - listTemplatingExtensions?(): Promise<ListTemplatingExtensionsResponse>; - - streamLogs(options: ScaffolderStreamLogsOptions): Observable<LogEvent>; - - dryRun?(options: ScaffolderDryRunOptions): Promise<ScaffolderDryRunResponse>; - - autocomplete?(options: { - token: string; - provider: string; - resource: string; - context?: Record<string, string>; - }): Promise<{ results: { title?: string; id: string }[] }>; -} +export type ScaffolderApi = _ScaffolderApi; diff --git a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts index 7712b91a18..67f47f70cb 100644 --- a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts +++ b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts @@ -16,13 +16,12 @@ import { ApiBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { formFieldsApiRef } from './ref'; -import { ScaffolderFormFieldsApi } from './types'; +import { FormField, ScaffolderFormFieldsApi } from './types'; import { FormFieldBlueprint } from '../blueprints'; -import { FormField, OpaqueFormField } from '@internal/scaffolder'; +import { OpaqueFormField } from '@internal/scaffolder'; class DefaultScaffolderFormFieldsApi implements ScaffolderFormFieldsApi { constructor( @@ -53,12 +52,12 @@ export const formFieldsApi = ApiBlueprint.makeWithOverrides({ e.get(FormFieldBlueprint.dataRefs.formFieldLoader), ); - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: formFieldsApiRef, deps: {}, factory: () => new DefaultScaffolderFormFieldsApi(formFieldLoaders), }), - }); + ); }, }); diff --git a/plugins/scaffolder-react/src/next/api/index.ts b/plugins/scaffolder-react/src/next/api/index.ts index ecc62e5acf..52c40ad99a 100644 --- a/plugins/scaffolder-react/src/next/api/index.ts +++ b/plugins/scaffolder-react/src/next/api/index.ts @@ -16,4 +16,4 @@ export { formFieldsApi } from './FormFieldsApi'; export { formFieldsApiRef } from './ref'; -export type { ScaffolderFormFieldsApi } from './types'; +export type { ScaffolderFormFieldsApi, FormField } from './types'; diff --git a/plugins/scaffolder-react/src/next/api/types.ts b/plugins/scaffolder-react/src/next/api/types.ts index ea93ba86b2..9e028567f6 100644 --- a/plugins/scaffolder-react/src/next/api/types.ts +++ b/plugins/scaffolder-react/src/next/api/types.ts @@ -23,3 +23,8 @@ import { FormFieldExtensionData } from '../blueprints'; export interface ScaffolderFormFieldsApi { getFormFields(): Promise<FormFieldExtensionData[]>; } + +/** @alpha */ +export interface FormField { + readonly $$type: '@backstage/scaffolder/FormField'; +} diff --git a/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx b/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx index 4324a080f6..afbf2b501d 100644 --- a/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx +++ b/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx @@ -19,8 +19,9 @@ import { } from '@backstage/frontend-plugin-api'; import { z } from 'zod'; -import { OpaqueFormField, FormField } from '@internal/scaffolder'; +import { OpaqueFormField } from '@internal/scaffolder'; import { FormFieldExtensionData } from './types'; +import { FormField } from '../api'; const formFieldExtensionDataRef = createExtensionDataRef< () => Promise<FormField> 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-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index 5f557198c6..5b724c5871 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -14,24 +14,13 @@ * limitations under the License. */ -import { JsonObject } from '@backstage/types'; - -import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateParameterSchema as _TemplateParameterSchema } from '@backstage/plugin-scaffolder-common'; /** * The shape of each entry of parameters which gets rendered * as a separate step in the wizard input * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#TemplateParameterSchema} instead as this has now been moved. */ -export type TemplateParameterSchema = { - title: string; - description?: string; - presentation?: TemplatePresentationV1beta3; - steps: Array<{ - title: string; - description?: string; - schema: JsonObject; - }>; - EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; -}; +export type TemplateParameterSchema = _TemplateParameterSchema; diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index a9fcc8001e..3e3a452000 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,133 @@ # @backstage/plugin-scaffolder +## 1.34.0-next.1 + +### Minor Changes + +- c08cbc4: Move Scaffolder API to OpenAPI + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- b0dc9b8: differentiate between entirely and partially composite schemas in schema rendering +- c4b7c50: Export `FormField` type from `/alpha` in `-react` package, and internal refactor. +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.19.0-next.1 + - @backstage/plugin-scaffolder-common@1.7.0-next.0 + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-react@0.4.36 + +## 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..c66f22f0a2 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.34.0-next.1", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", @@ -79,7 +79,6 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@microsoft/fetch-event-source": "^2.0.1", "@react-hookz/web": "^24.0.0", "@rjsf/core": "5.23.2", "@rjsf/material-ui": "5.23.2", @@ -100,7 +99,6 @@ "react-use": "^17.2.4", "react-window": "^1.8.10", "yaml": "^2.0.0", - "zen-observable": "^0.10.0", "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" }, @@ -120,7 +118,6 @@ "@types/react": "^18.0.0", "@types/react-resizable": "^3.0.8", "@types/react-window": "^1.8.8", - "msw": "^1.0.0", "react": "^18.0.2", "react-dom": "^18.0.2", "react-router-dom": "^6.3.0", diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 509cfa8497..38b1ee717b 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -5,16 +5,18 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ApiRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import { FormField } from '@internal/scaffolder'; +import { FormField } from '@backstage/plugin-scaffolder-react/alpha'; import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; import type { FormProps as FormProps_2 } from '@rjsf/core'; import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; @@ -66,9 +68,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'api:scaffolder/form-decorators': ExtensionDefinition<{ config: {}; @@ -93,9 +99,13 @@ const _default: FrontendPlugin< }; kind: 'api'; name: 'form-decorators'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'api:scaffolder/form-fields': ExtensionDefinition<{ config: {}; @@ -120,9 +130,13 @@ const _default: FrontendPlugin< }; kind: 'api'; name: 'form-fields'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'entity-icon-link:scaffolder/launch-template': ExtensionDefinition<{ kind: 'entity-icon-link'; @@ -273,9 +287,13 @@ export const formDecoratorsApi: ExtensionDefinition<{ }; kind: 'api'; name: 'form-decorators'; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; // @alpha (undocumented) diff --git a/plugins/scaffolder/report.api.md b/plugins/scaffolder/report.api.md index b44889cded..fbb73f6225 100644 --- a/plugins/scaffolder/report.api.md +++ b/plugins/scaffolder/report.api.md @@ -11,47 +11,43 @@ import { createScaffolderFieldExtension as createScaffolderFieldExtension_2 } fr import { createScaffolderLayout as createScaffolderLayout_2 } from '@backstage/plugin-scaffolder-react'; import { CustomFieldExtensionSchema as CustomFieldExtensionSchema_2 } from '@backstage/plugin-scaffolder-react'; import { CustomFieldValidator as CustomFieldValidator_2 } from '@backstage/plugin-scaffolder-react'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; -import { FetchApi } from '@backstage/core-plugin-api'; import { FieldExtensionComponent as FieldExtensionComponent_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionComponentProps as FieldExtensionComponentProps_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionOptions as FieldExtensionOptions_2 } from '@backstage/plugin-scaffolder-react'; import { FieldSchema as FieldSchema_2 } from '@backstage/plugin-scaffolder-react'; import { FieldValidation } from '@rjsf/utils'; import { FormProps } from '@backstage/plugin-scaffolder-react'; -import { IdentityApi } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react/jsx-runtime'; import { LayoutOptions as LayoutOptions_2 } from '@backstage/plugin-scaffolder-react'; import { LayoutTemplate as LayoutTemplate_2 } from '@backstage/plugin-scaffolder-react'; -import { ListActionsResponse as ListActionsResponse_2 } from '@backstage/plugin-scaffolder-react'; -import { ListTemplatingExtensionsResponse } from '@backstage/plugin-scaffolder-react'; -import { LogEvent as LogEvent_2 } from '@backstage/plugin-scaffolder-react'; -import { Observable } from '@backstage/types'; +import { ListActionsResponse as ListActionsResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { LogEvent as LogEvent_2 } from '@backstage/plugin-scaffolder-common'; import { PathParams } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; import { ReactNode } from 'react'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { RouteRef } from '@backstage/core-plugin-api'; -import { ScaffolderApi as ScaffolderApi_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderDryRunOptions as ScaffolderDryRunOptions_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderDryRunResponse as ScaffolderDryRunResponse_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderGetIntegrationsListOptions as ScaffolderGetIntegrationsListOptions_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderGetIntegrationsListResponse as ScaffolderGetIntegrationsListResponse_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderOutputLink } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderScaffoldOptions as ScaffolderScaffoldOptions_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderScaffoldResponse as ScaffolderScaffoldResponse_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderStreamLogsOptions as ScaffolderStreamLogsOptions_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderTask as ScaffolderTask_2 } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderApi as ScaffolderApi_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderClient as ScaffolderClient_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderDryRunOptions as ScaffolderDryRunOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderDryRunResponse as ScaffolderDryRunResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderGetIntegrationsListOptions as ScaffolderGetIntegrationsListOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderGetIntegrationsListResponse as ScaffolderGetIntegrationsListResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderOutputLink } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderScaffoldOptions as ScaffolderScaffoldOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderScaffoldResponse as ScaffolderScaffoldResponse_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderStreamLogsOptions as ScaffolderStreamLogsOptions_2 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderTask as ScaffolderTask_2 } from '@backstage/plugin-scaffolder-common'; import { ScaffolderTaskOutput as ScaffolderTaskOutput_2 } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderTaskStatus as ScaffolderTaskStatus_2 } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderTaskOutput as ScaffolderTaskOutput_3 } from '@backstage/plugin-scaffolder-common'; +import { ScaffolderTaskStatus as ScaffolderTaskStatus_2 } from '@backstage/plugin-scaffolder-common'; import { ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecrets_2 } from '@backstage/plugin-scaffolder-react'; -import { ScmIntegrationRegistry } from '@backstage/integration'; import { SubRouteRef } from '@backstage/core-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; import { TemplateListPageProps } from '@backstage/plugin-scaffolder/alpha'; -import { TemplateParameterSchema as TemplateParameterSchema_2 } from '@backstage/plugin-scaffolder-react'; +import { TemplateParameterSchema as TemplateParameterSchema_2 } from '@backstage/plugin-scaffolder-common'; import { TemplateWizardPageProps } from '@backstage/plugin-scaffolder/alpha'; import { z } from 'zod'; @@ -505,70 +501,8 @@ export type ScaffolderApi = ScaffolderApi_2; // @public @deprecated (undocumented) export const scaffolderApiRef: ApiRef<ScaffolderApi_2>; -// @public -export class ScaffolderClient implements ScaffolderApi_2 { - constructor(options: { - discoveryApi: DiscoveryApi; - fetchApi: FetchApi; - identityApi?: IdentityApi; - scmIntegrationsApi: ScmIntegrationRegistry; - useLongPollingLogs?: boolean; - }); - // (undocumented) - autocomplete({ - token, - resource, - provider, - context, - }: { - token: string; - provider: string; - resource: string; - context?: Record<string, string>; - }): Promise<{ - results: { - title?: string; - id: string; - }[]; - }>; - // (undocumented) - cancelTask(taskId: string): Promise<void>; - // (undocumented) - dryRun( - options: ScaffolderDryRunOptions_2, - ): Promise<ScaffolderDryRunResponse_2>; - // (undocumented) - getIntegrationsList( - options: ScaffolderGetIntegrationsListOptions_2, - ): Promise<ScaffolderGetIntegrationsListResponse_2>; - // (undocumented) - getTask(taskId: string): Promise<ScaffolderTask_2>; - // (undocumented) - getTemplateParameterSchema( - templateRef: string, - ): Promise<TemplateParameterSchema_2>; - // (undocumented) - listActions(): Promise<ListActionsResponse_2>; - // (undocumented) - listTasks(options: { - filterByOwnership: 'owned' | 'all'; - limit?: number; - offset?: number; - }): Promise<{ - tasks: ScaffolderTask_2[]; - totalTasks?: number; - }>; - // (undocumented) - listTemplatingExtensions(): Promise<ListTemplatingExtensionsResponse>; - // (undocumented) - retry?(taskId: string): Promise<void>; - // (undocumented) - scaffold( - options: ScaffolderScaffoldOptions_2, - ): Promise<ScaffolderScaffoldResponse_2>; - // (undocumented) - streamLogs(options: ScaffolderStreamLogsOptions_2): Observable<LogEvent_2>; -} +// @public @deprecated +export class ScaffolderClient extends ScaffolderClient_2 {} // @public @deprecated (undocumented) export type ScaffolderDryRunOptions = ScaffolderDryRunOptions_2; @@ -644,7 +578,7 @@ export type ScaffolderStreamLogsOptions = ScaffolderStreamLogsOptions_2; export type ScaffolderTask = ScaffolderTask_2; // @public @deprecated (undocumented) -export type ScaffolderTaskOutput = ScaffolderTaskOutput_2; +export type ScaffolderTaskOutput = ScaffolderTaskOutput_3; // @public @deprecated (undocumented) export type ScaffolderTaskStatus = ScaffolderTaskStatus_2; diff --git a/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts index 41bf91dba0..4ae975ec5a 100644 --- a/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts +++ b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts @@ -16,7 +16,6 @@ import { ApiBlueprint, - createApiFactory, createExtensionInput, } from '@backstage/frontend-plugin-api'; import { ScaffolderFormDecoratorsApi } from './types'; @@ -58,8 +57,8 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({ e.get(FormDecoratorBlueprint.dataRefs.formDecoratorLoader), ); - return originalFactory({ - factory: createApiFactory({ + return originalFactory(define => + define({ api: formDecoratorsApiRef, deps: {}, factory: () => @@ -67,6 +66,6 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({ decorators: formDecorators, }), }), - }); + ); }, }); diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 2657565a38..5cbe524d3e 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -118,7 +118,7 @@ async function downloadDirectoryContents( directoryContents: { path: string; base64Content: string; - executable: boolean; + executable?: boolean; }[], name: string, ) { 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/alpha/extensions.tsx b/plugins/scaffolder/src/alpha/extensions.tsx index 7c82edc97f..351ad4ed56 100644 --- a/plugins/scaffolder/src/alpha/extensions.tsx +++ b/plugins/scaffolder/src/alpha/extensions.tsx @@ -22,7 +22,6 @@ import { NavItemBlueprint, PageBlueprint, ApiBlueprint, - createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef, @@ -74,8 +73,8 @@ export const repoUrlPickerFormField = FormFieldBlueprint.make({ }); export const scaffolderApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: scaffolderApiRef, deps: { discoveryApi: discoveryApiRef, @@ -91,5 +90,4 @@ export const scaffolderApi = ApiBlueprint.make({ identityApi, }), }), - }, }); diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 4fb3627917..d880521cf2 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -14,389 +14,12 @@ * limitations under the License. */ -import { parseEntityRef } from '@backstage/catalog-model'; -import { - DiscoveryApi, - FetchApi, - IdentityApi, -} from '@backstage/core-plugin-api'; -import { ResponseError } from '@backstage/errors'; -import { ScmIntegrationRegistry } from '@backstage/integration'; -import { - ListActionsResponse, - ListTemplatingExtensionsResponse, - LogEvent, - ScaffolderApi, - ScaffolderDryRunOptions, - ScaffolderDryRunResponse, - ScaffolderGetIntegrationsListOptions, - ScaffolderGetIntegrationsListResponse, - ScaffolderScaffoldOptions, - ScaffolderScaffoldResponse, - ScaffolderStreamLogsOptions, - ScaffolderTask, - TemplateParameterSchema, -} from '@backstage/plugin-scaffolder-react'; -import { Observable } from '@backstage/types'; -import { - EventSourceMessage, - fetchEventSource, -} from '@microsoft/fetch-event-source'; -import { default as qs, default as queryString } from 'qs'; -import ObservableImpl from 'zen-observable'; +import { ScaffolderClient as _ScaffolderClient } from '@backstage/plugin-scaffolder-common'; /** * An API to interact with the scaffolder backend. * * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderClient} instead as this has now been moved. */ -export class ScaffolderClient implements ScaffolderApi { - private readonly discoveryApi: DiscoveryApi; - private readonly scmIntegrationsApi: ScmIntegrationRegistry; - private readonly fetchApi: FetchApi; - private readonly identityApi?: IdentityApi; - private readonly useLongPollingLogs: boolean; - - constructor(options: { - discoveryApi: DiscoveryApi; - fetchApi: FetchApi; - identityApi?: IdentityApi; - scmIntegrationsApi: ScmIntegrationRegistry; - useLongPollingLogs?: boolean; - }) { - this.discoveryApi = options.discoveryApi; - this.fetchApi = options.fetchApi ?? { fetch }; - this.scmIntegrationsApi = options.scmIntegrationsApi; - this.useLongPollingLogs = options.useLongPollingLogs ?? false; - this.identityApi = options.identityApi; - } - - async listTasks(options: { - filterByOwnership: 'owned' | 'all'; - limit?: number; - offset?: number; - }): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }> { - if (!this.identityApi) { - throw new Error( - 'IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method', - ); - } - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const { userEntityRef } = await this.identityApi.getBackstageIdentity(); - - const query = queryString.stringify({ - createdBy: - options.filterByOwnership === 'owned' ? userEntityRef : undefined, - limit: options.limit, - offset: options.offset, - }); - - const response = await this.fetchApi.fetch(`${baseUrl}/v2/tasks?${query}`); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return await response.json(); - } - - async getIntegrationsList( - options: ScaffolderGetIntegrationsListOptions, - ): Promise<ScaffolderGetIntegrationsListResponse> { - const integrations = [ - ...this.scmIntegrationsApi.azure.list(), - ...this.scmIntegrationsApi.bitbucket - .list() - .filter( - item => - !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && - !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host), - ), - ...this.scmIntegrationsApi.bitbucketCloud.list(), - ...this.scmIntegrationsApi.bitbucketServer.list(), - ...this.scmIntegrationsApi.gerrit.list(), - ...this.scmIntegrationsApi.gitea.list(), - ...this.scmIntegrationsApi.github.list(), - ...this.scmIntegrationsApi.gitlab.list(), - ] - .map(c => ({ type: c.type, title: c.title, host: c.config.host })) - .filter(c => options.allowedHosts.includes(c.host)); - - return { - integrations, - }; - } - - async getTemplateParameterSchema( - templateRef: string, - ): Promise<TemplateParameterSchema> { - const { namespace, kind, name } = parseEntityRef(templateRef, { - defaultKind: 'template', - }); - - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const templatePath = [namespace, kind, name] - .map(s => encodeURIComponent(s)) - .join('/'); - - const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`; - - const response = await this.fetchApi.fetch(url); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - const schema: TemplateParameterSchema = await response.json(); - return schema; - } - - async scaffold( - options: ScaffolderScaffoldOptions, - ): Promise<ScaffolderScaffoldResponse> { - const { templateRef, values, secrets = {} } = options; - const url = `${await this.discoveryApi.getBaseUrl('scaffolder')}/v2/tasks`; - const response = await this.fetchApi.fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - templateRef, - values: { ...values }, - secrets, - }), - }); - - if (response.status !== 201) { - const status = `${response.status} ${response.statusText}`; - const body = await response.text(); - throw new Error(`Backend request failed, ${status} ${body.trim()}`); - } - - const { id } = (await response.json()) as { id: string }; - return { taskId: id }; - } - - async getTask(taskId: string): Promise<ScaffolderTask> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`; - - const response = await this.fetchApi.fetch(url); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return await response.json(); - } - - streamLogs(options: ScaffolderStreamLogsOptions): Observable<LogEvent> { - if (this.useLongPollingLogs) { - return this.streamLogsPolling(options); - } - - return this.streamLogsEventStream(options); - } - - async dryRun( - options: ScaffolderDryRunOptions, - ): Promise<ScaffolderDryRunResponse> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const response = await this.fetchApi.fetch(`${baseUrl}/v2/dry-run`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - template: options.template, - values: options.values, - secrets: options.secrets, - directoryContents: options.directoryContents, - }), - }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return response.json(); - } - - private streamLogsEventStream({ - isTaskRecoverable, - taskId, - after, - }: ScaffolderStreamLogsOptions): Observable<LogEvent> { - return new ObservableImpl(subscriber => { - const params = new URLSearchParams(); - if (after !== undefined) { - params.set('after', String(Number(after))); - } - - this.discoveryApi.getBaseUrl('scaffolder').then( - baseUrl => { - const url = `${baseUrl}/v2/tasks/${encodeURIComponent( - taskId, - )}/eventstream`; - - const processEvent = (event: any) => { - if (event.data) { - try { - subscriber.next(JSON.parse(event.data)); - } catch (ex) { - subscriber.error(ex); - } - } - }; - - const ctrl = new AbortController(); - void fetchEventSource(url, { - fetch: this.fetchApi.fetch, - signal: ctrl.signal, - onmessage(e: EventSourceMessage) { - if (e.event === 'log') { - processEvent(e); - return; - } else if (e.event === 'completion' && !isTaskRecoverable) { - processEvent(e); - subscriber.complete(); - ctrl.abort(); - return; - } - processEvent(e); - }, - onerror(err) { - subscriber.error(err); - }, - }); - }, - error => { - subscriber.error(error); - }, - ); - }); - } - - private streamLogsPolling({ - taskId, - after: inputAfter, - }: { - taskId: string; - after?: number; - }): Observable<LogEvent> { - let after = inputAfter; - - return new ObservableImpl(subscriber => { - this.discoveryApi.getBaseUrl('scaffolder').then(async baseUrl => { - while (!subscriber.closed) { - const url = `${baseUrl}/v2/tasks/${encodeURIComponent( - taskId, - )}/events?${qs.stringify({ after })}`; - const response = await this.fetchApi.fetch(url); - - if (!response.ok) { - // wait for one second to not run into an - await new Promise(resolve => setTimeout(resolve, 1000)); - continue; - } - - const logs = (await response.json()) as LogEvent[]; - - for (const event of logs) { - after = Number(event.id); - - subscriber.next(event); - - if (event.type === 'completion') { - subscriber.complete(); - return; - } - } - } - }); - }); - } - - async listActions(): Promise<ListActionsResponse> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const response = await this.fetchApi.fetch(`${baseUrl}/v2/actions`); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return await response.json(); - } - - async listTemplatingExtensions(): Promise<ListTemplatingExtensionsResponse> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const response = await this.fetchApi.fetch( - `${baseUrl}/v2/templating-extensions`, - ); - if (!response.ok) { - throw ResponseError.fromResponse(response); - } - return response.json(); - } - - async cancelTask(taskId: string): Promise<void> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/cancel`; - - const response = await this.fetchApi.fetch(url, { - method: 'POST', - }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return await response.json(); - } - - async retry?(taskId: string): Promise<void> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/retry`; - - const response = await this.fetchApi.fetch(url, { - method: 'POST', - }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return await response.json(); - } - - async autocomplete({ - token, - resource, - provider, - context, - }: { - token: string; - provider: string; - resource: string; - context?: Record<string, string>; - }): Promise<{ results: { title?: string; id: string }[] }> { - const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - - const url = `${baseUrl}/v2/autocomplete/${provider}/${resource}`; - - const response = await this.fetchApi.fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - token, - context: context ?? {}, - }), - }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - const { results } = await response.json(); - return { results }; - } -} +export class ScaffolderClient extends _ScaffolderClient {} 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/RenderSchema/RenderSchema.tsx b/plugins/scaffolder/src/components/RenderSchema/RenderSchema.tsx index fc926e6c44..2d4ebd6fca 100644 --- a/plugins/scaffolder/src/components/RenderSchema/RenderSchema.tsx +++ b/plugins/scaffolder/src/components/RenderSchema/RenderSchema.tsx @@ -102,6 +102,9 @@ const getSubschemas = (schema: JSONSchema7Definition): subSchemasType => { base[key as Exclude<keyof JSONSchema7, keyof subSchemasType>] = value; } } + if (!(base?.type === 'object' || 'properties' in base)) { + return subschemas; + } return Object.fromEntries( Object.entries(subschemas).map(([key, sub]) => { const mergedSubschema = sub.map(alt => { @@ -358,13 +361,15 @@ export const RenderSchema = ({ let columns: Column[] | undefined; let elements: SchemaRenderElement[] | undefined; if (strategy === 'root') { - elements = [{ schema }]; - columns = [typeColumn]; - if (schema.description) { - columns.unshift(descriptionColumn); - } - if (schema.title) { - columns.unshift(titleColumn); + if ('type' in schema || !Object.keys(subschemas).length) { + elements = [{ schema }]; + columns = [typeColumn]; + if (schema.description) { + columns.unshift(descriptionColumn); + } + if (schema.title) { + columns.unshift(titleColumn); + } } } else if (schema.properties) { columns = [nameColumn, titleColumn, descriptionColumn, typeColumn]; diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index 91567c1ddd..a57811a520 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -60,14 +60,12 @@ 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 { OpaqueFormField } from '@internal/scaffolder'; import { useAsync, useMountEffect } from '@react-hookz/web'; import { TemplatingExtensionsPage } from '../TemplatingExtensionsPage'; +import { FormField } from '@backstage/plugin-scaffolder-react/alpha'; /** * The Props for the Scaffolder Router @@ -182,11 +180,9 @@ export const InternalRouter = ( <Route path={scaffolderTaskRouteRef.path} element={ - <RequirePermission permission={taskReadPermission}> - <TaskPageComponent - TemplateOutputsComponent={TemplateOutputsComponent} - /> - </RequirePermission> + <TaskPageComponent + TemplateOutputsComponent={TemplateOutputsComponent} + /> } /> <Route @@ -230,11 +226,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/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 696b33e9d0..f5861d4946 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -85,6 +85,7 @@ export const BitbucketRepoPicker = ( scaffolderApi .autocomplete({ + context: {}, token: accessToken, resource: 'workspaces', provider: 'bitbucket-cloud', diff --git a/plugins/scaffolder/src/deprecated.ts b/plugins/scaffolder/src/deprecated.ts index 907871946c..f3230ab287 100644 --- a/plugins/scaffolder/src/deprecated.ts +++ b/plugins/scaffolder/src/deprecated.ts @@ -21,22 +21,8 @@ */ import { - createScaffolderFieldExtension as createScaffolderFieldExtensionTemp, - ScaffolderFieldExtensions as ScaffolderFieldExtensionsTemp, - useTemplateSecrets as useTemplateSecretsTemp, - scaffolderApiRef as scaffolderApiRefTemp, - createScaffolderLayout as createScaffolderLayoutTemp, - ScaffolderLayouts as ScaffolderLayoutsTemp, - type LayoutOptions as LayoutOptionsTemp, - type LayoutTemplate as LayoutTemplateTemp, type ScaffolderApi as ScaffolderApiTemp, - type ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecretsTemp, type TemplateParameterSchema as TemplateParameterSchemaTemp, - type CustomFieldExtensionSchema as CustomFieldExtensionSchemaTemp, - type CustomFieldValidator as CustomFieldValidatorTemp, - type FieldExtensionOptions as FieldExtensionOptionsTemp, - type FieldExtensionComponentProps as FieldExtensionComponentPropsTemp, - type FieldExtensionComponent as FieldExtensionComponentTemp, type ListActionsResponse as ListActionsResponseTemp, type LogEvent as LogEventTemp, type ScaffolderDryRunOptions as ScaffolderDryRunOptionsTemp, @@ -50,6 +36,23 @@ import { type ScaffolderTask as ScaffolderTaskTemp, type ScaffolderTaskOutput as ScaffolderTaskOutputTemp, type ScaffolderTaskStatus as ScaffolderTaskStatusTemp, +} from '@backstage/plugin-scaffolder-common'; + +import { + createScaffolderFieldExtension as createScaffolderFieldExtensionTemp, + ScaffolderFieldExtensions as ScaffolderFieldExtensionsTemp, + useTemplateSecrets as useTemplateSecretsTemp, + scaffolderApiRef as scaffolderApiRefTemp, + createScaffolderLayout as createScaffolderLayoutTemp, + ScaffolderLayouts as ScaffolderLayoutsTemp, + type LayoutOptions as LayoutOptionsTemp, + type LayoutTemplate as LayoutTemplateTemp, + type ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecretsTemp, + type CustomFieldExtensionSchema as CustomFieldExtensionSchemaTemp, + type CustomFieldValidator as CustomFieldValidatorTemp, + type FieldExtensionOptions as FieldExtensionOptionsTemp, + type FieldExtensionComponentProps as FieldExtensionComponentPropsTemp, + type FieldExtensionComponent as FieldExtensionComponentTemp, } from '@backstage/plugin-scaffolder-react'; import { rootRouteRef as rootRouteRefTemp } from './routes'; @@ -82,7 +85,7 @@ export const useTemplateSecrets = useTemplateSecretsTemp; export const scaffolderApiRef = scaffolderApiRefTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderApi} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderApi} instead as this has now been moved. */ export type ScaffolderApi = ScaffolderApiTemp; /** @@ -92,7 +95,7 @@ export type ScaffolderApi = ScaffolderApiTemp; export type ScaffolderUseTemplateSecrets = ScaffolderUseTemplateSecretsTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#TemplateParameterSchema} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#TemplateParameterSchema} instead as this has now been moved. */ export type TemplateParameterSchema = TemplateParameterSchemaTemp; /** @@ -127,69 +130,69 @@ export type FieldExtensionComponent<_TReturnValue, _TInputProps> = FieldExtensionComponentTemp<_TReturnValue, _TInputProps>; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ListActionsResponse} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ListActionsResponse} instead as this has now been moved. */ export type ListActionsResponse = ListActionsResponseTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#LogEvent} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#LogEvent} instead as this has now been moved. */ export type LogEvent = LogEventTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderDryRunOptions} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderDryRunOptions} instead as this has now been moved. */ export type ScaffolderDryRunOptions = ScaffolderDryRunOptionsTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderDryRunResponse} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderDryRunResponse} instead as this has now been moved. */ export type ScaffolderDryRunResponse = ScaffolderDryRunResponseTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderGetIntegrationsListOptions} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderGetIntegrationsListOptions} instead as this has now been moved. */ export type ScaffolderGetIntegrationsListOptions = ScaffolderGetIntegrationsListOptionsTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderGetIntegrationsListResponse} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderGetIntegrationsListResponse} instead as this has now been moved. */ export type ScaffolderGetIntegrationsListResponse = ScaffolderGetIntegrationsListResponseTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderOutputlink} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderOutputlink} instead as this has now been moved. */ export type ScaffolderOutputlink = ScaffolderOutputLinkTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderScaffoldOptions} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderScaffoldOptions} instead as this has now been moved. */ export type ScaffolderScaffoldOptions = ScaffolderScaffoldOptionsTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderScaffoldResponse} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderScaffoldResponse} instead as this has now been moved. */ export type ScaffolderScaffoldResponse = ScaffolderScaffoldResponseTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderStreamLogsOptions} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderStreamLogsOptions} instead as this has now been moved. */ export type ScaffolderStreamLogsOptions = ScaffolderStreamLogsOptionsTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderTask} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTask} instead as this has now been moved. */ export type ScaffolderTask = ScaffolderTaskTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderTaskOutput} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTaskOutput} instead as this has now been moved. */ export type ScaffolderTaskOutput = ScaffolderTaskOutputTemp; /** * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderTaskStatus} instead as this has now been moved. + * @deprecated use import from {@link @backstage/plugin-scaffolder-common#ScaffolderTaskStatus} instead as this has now been moved. */ export type ScaffolderTaskStatus = ScaffolderTaskStatusTemp; /** diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 14cb48f3a0..5ad6441fc1 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-search-backend-module-catalog +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-search-common@1.2.19 + +## 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..7cecf8e24a 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.7-next.0", "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..ab1724ef3f 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.7.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-search-common@1.2.19 + +## 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..2f07184948 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.5-next.0", "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..fece49ed99 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-search-backend-module-explore +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/plugin-search-common@1.2.19 + +## 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..bf910db383 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.5-next.0", "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..4de8332639 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/plugin-search-common@1.2.19 + +## 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..1e4450cd0f 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.47-next.0", "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..f153ca4b2b 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/plugin-search-common@1.2.19 + +## 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..2e31d85d7d 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.12-next.0", "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..dd16923cb8 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-techdocs-node@1.13.6-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-search-common@1.2.19 + +## 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..301aa7827e 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.5-next.0", "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..5963068f3f 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-search-backend-node +## 1.3.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-search-common@1.2.19 + +## 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..dfcbff9383 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.14-next.0", "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..064d1b5530 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/plugin-search-backend +## 2.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/backend-openapi-utils@0.6.0-next.0 + - @backstage/plugin-permission-node@0.10.3-next.0 + - @backstage/plugin-search-backend-node@1.3.14-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-search-common@1.2.19 + +## 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..bf9ab8b523 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.5-next.0", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-backend/src/service/router.test.ts b/plugins/search-backend/src/service/router.test.ts index 5aea71b7c1..623b78016a 100644 --- a/plugins/search-backend/src/service/router.test.ts +++ b/plugins/search-backend/src/service/router.test.ts @@ -106,7 +106,7 @@ describe('createRouter', () => { expect.objectContaining({ error: { name: 'Error', - message: `There was a problem performing the search query: ${error.message}`, + message: `There was a problem performing the search query`, }, }), ); diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index 0ba5eede81..eedd84105a 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -197,14 +197,17 @@ export async function createRouter( res.json(filterResultSet(toSearchResults(resultSet))); } catch (error) { + // Log the error message here, but don't expose it to the user in the response + logger.error( + `There was a problem performing the search query: ${error.message}`, + ); if (error.name === 'MissingIndexError') { // re-throw and let the default error handler middleware captures it and serializes it with the right response code on the standard form throw error; } - throw new Error( - `There was a problem performing the search query: ${error.message}`, - ); + // If the error is not a MissingIndexError, we want to throw a generic error without the error message as it may leak internal information + throw new Error(`There was a problem performing the search query`); } }); 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..498b02f959 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-search-react +## 1.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.19 + +## 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..9f85419cc6 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.3-next.0", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 7d6e4248de..b35205d995 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,74 @@ # @backstage/plugin-search +## 1.4.29-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/plugin-search-react@1.9.3-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.19 + +## 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..e0ac64709a 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.1", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index 3af0384d89..1edc5e678d 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -5,7 +5,9 @@ ```ts import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/core-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -35,9 +37,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'nav-item:search': ExtensionDefinition<{ kind: 'nav-item'; @@ -145,9 +151,13 @@ export const searchApi: ExtensionDefinition<{ configInput: {}; output: ConfigurableExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; // @alpha (undocumented) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 136f95f39e..5028a404d4 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -31,7 +31,6 @@ import { useApi, discoveryApiRef, fetchApiRef, - createApiFactory, } from '@backstage/core-plugin-api'; import { @@ -77,14 +76,13 @@ import { /** @alpha */ export const searchApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: searchApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, factory: ({ discoveryApi, fetchApi }) => new SearchClient({ discoveryApi, fetchApi }), }), - }, }); const useSearchPageStyles = makeStyles((theme: Theme) => ({ diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index daa8f03014..579abe991c 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-signals-backend +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-node@0.1.23-next.0 + +## 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..5e6aad0197 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.7-next.0", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index d24f1cc0b1..ad280ee31b 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-signals-node +## 0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-events-node@0.4.14-next.0 + - @backstage/config@1.3.3 + - @backstage/types@1.2.1 + +## 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..e3cc09a877 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.23-next.0", "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..a88fa814af 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/plugin-signals +## 0.0.22-next.1 + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.15 + +## 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..e8ee6fea2f 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.1", "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..13091a9032 100644 --- a/plugins/signals/report-alpha.api.md +++ b/plugins/signals/report-alpha.api.md @@ -4,9 +4,12 @@ ```ts import { AnyApiFactory } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionBlueprintParams } 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< @@ -24,8 +27,27 @@ const _default: FrontendPlugin< {} >; inputs: {}; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<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: { - factory: AnyApiFactory; + element: JSX.Element | (() => JSX.Element); }; }>; } diff --git a/plugins/signals/src/alpha.tsx b/plugins/signals/src/alpha.tsx index 90b78b05fd..340425bebd 100644 --- a/plugins/signals/src/alpha.tsx +++ b/plugins/signals/src/alpha.tsx @@ -16,17 +16,19 @@ import { ApiBlueprint, - createApiFactory, + AppRootElementBlueprint, createFrontendPlugin, discoveryApiRef, identityApiRef, } 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: { - factory: createApiFactory({ + params: define => + define({ api: signalApiRef, deps: { identity: identityApiRef, @@ -39,6 +41,12 @@ const api = ApiBlueprint.make({ }); }, }), +}); + +const signalsDisplayAppRootElement = AppRootElementBlueprint.make({ + name: 'signals-display', + params: { + element: compatWrapper(<SignalsDisplay />), }, }); @@ -46,5 +54,5 @@ const api = ApiBlueprint.make({ 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..24df3849fd 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,89 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.31.2-next.1 + - @backstage/plugin-techdocs@1.14.0-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/plugin-search-react@1.9.3-next.0 + - @backstage/plugin-techdocs-react@1.3.2-next.0 + - @backstage/test-utils@1.7.11-next.0 + - @backstage/core-app-api@1.18.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration-react@1.2.9 + +## 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..54d36af0f2 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.1", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index f4d3b62cca..e03af42435 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,77 @@ # @backstage/plugin-techdocs-backend +## 2.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.18.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.5-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/plugin-techdocs-node@1.13.6-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/plugin-catalog-common@1.1.5 + - @backstage/plugin-permission-common@0.9.1 + - @backstage/plugin-techdocs-common@0.1.1 + +## 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..d29c5054fc 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.5-next.0", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts b/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts index 2eb6bf03f4..df5c038dce 100644 --- a/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts +++ b/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts @@ -18,9 +18,11 @@ import { CachedEntityLoader } from './CachedEntityLoader'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { mockServices } from '@backstage/backend-test-utils'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; describe('CachedEntityLoader', () => { const cache = mockServices.cache.mock(); + const auth = mockServices.auth.mock(); const entityName: CompoundEntityRef = { kind: 'component', @@ -39,20 +41,37 @@ describe('CachedEntityLoader', () => { const token = 'test-token'; + const userCredentials: BackstageCredentials = { + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'user', + userEntityRef: 'user:default/test-user', + }, + }; + + const pluginCredentials: BackstageCredentials = { + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'plugin', + subject: 'plugin:test-plugin', + }, + }; + afterEach(() => { jest.resetAllMocks(); }); - it('writes entities to cache', async () => { + it('writes entities to cache for user credentials', async () => { cache.get.mockResolvedValue(undefined); const catalog = catalogServiceMock({ entities: [entity] }); + auth.isPrincipal.mockReturnValue(true); - const loader = new CachedEntityLoader({ catalog, cache }); - const result = await loader.load(entityName, token); + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(userCredentials, entityName, token); expect(result).toEqual(entity); expect(cache.set).toHaveBeenCalledWith( - 'catalog:component:default/test:test-token', + 'catalog:component:default/test:user:default/test-user', entity, { ttl: 5000 }, ); @@ -62,9 +81,10 @@ describe('CachedEntityLoader', () => { const catalog = catalogServiceMock(); jest.spyOn(catalog, 'getEntityByRef'); cache.get.mockResolvedValue(entity); + auth.isPrincipal.mockReturnValue(true); - const loader = new CachedEntityLoader({ catalog, cache }); - const result = await loader.load(entityName, token); + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(userCredentials, entityName, token); expect(result).toEqual(entity); expect(catalog.getEntityByRef).not.toHaveBeenCalled(); @@ -73,24 +93,26 @@ describe('CachedEntityLoader', () => { it('does not cache missing entities', async () => { const catalog = catalogServiceMock({ entities: [] }); cache.get.mockResolvedValue(undefined); + auth.isPrincipal.mockReturnValue(true); - const loader = new CachedEntityLoader({ catalog, cache }); - const result = await loader.load(entityName, token); + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(userCredentials, entityName, token); expect(result).toBeUndefined(); expect(cache.set).not.toHaveBeenCalled(); }); - it('uses entity ref as cache key for anonymous users', async () => { + it('uses entity ref as cache key for service credentials', async () => { const catalog = catalogServiceMock({ entities: [entity] }); cache.get.mockResolvedValue(undefined); + auth.isPrincipal.mockReturnValueOnce(false).mockReturnValueOnce(true); - const loader = new CachedEntityLoader({ catalog, cache }); - const result = await loader.load(entityName, undefined); + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(pluginCredentials, entityName, undefined); expect(result).toEqual(entity); expect(cache.set).toHaveBeenCalledWith( - 'catalog:component:default/test', + 'catalog:component:default/test:plugin:test-plugin', entity, { ttl: 5000, @@ -106,10 +128,82 @@ describe('CachedEntityLoader', () => { }), ); const catalog = catalogServiceMock({ entities: [entity] }); + auth.isPrincipal.mockReturnValue(true); - const loader = new CachedEntityLoader({ catalog, cache }); - const result = await loader.load(entityName, token); + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(userCredentials, entityName, token); expect(result).toEqual(entity); }); + + it('creates different cache keys for different users', async () => { + const catalog = catalogServiceMock({ entities: [entity] }); + cache.get.mockResolvedValue(undefined); + auth.isPrincipal.mockReturnValue(true); + + const loader = new CachedEntityLoader({ auth, catalog, cache }); + + const anotherUserCredentials: BackstageCredentials = { + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'user', + userEntityRef: 'user:default/another-user', + }, + }; + + await loader.load(userCredentials, entityName, token); + await loader.load(anotherUserCredentials, entityName, token); + + expect(cache.set).toHaveBeenCalledWith( + 'catalog:component:default/test:user:default/test-user', + entity, + { ttl: 5000 }, + ); + expect(cache.set).toHaveBeenCalledWith( + 'catalog:component:default/test:user:default/another-user', + entity, + { ttl: 5000 }, + ); + }); + + it('creates cache key with service subject for service credentials', async () => { + const catalog = catalogServiceMock({ entities: [entity] }); + cache.get.mockResolvedValue(undefined); + auth.isPrincipal.mockReturnValueOnce(false).mockReturnValueOnce(true); + + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(pluginCredentials, entityName, token); + + expect(result).toEqual(entity); + expect(cache.set).toHaveBeenCalledWith( + 'catalog:component:default/test:plugin:test-plugin', + entity, + { ttl: 5000 }, + ); + expect(auth.isPrincipal).toHaveBeenCalledWith(pluginCredentials, 'user'); + expect(auth.isPrincipal).toHaveBeenCalledWith(pluginCredentials, 'service'); + }); + + it('handles credentials that are neither user nor service', async () => { + const catalog = catalogServiceMock({ entities: [entity] }); + cache.get.mockResolvedValue(undefined); + auth.isPrincipal.mockReturnValue(false); + + const unknownCredentials: BackstageCredentials = { + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'unknown' as any, + }, + }; + + const loader = new CachedEntityLoader({ auth, catalog, cache }); + const result = await loader.load(unknownCredentials, entityName, token); + + expect(result).toEqual(entity); + expect(cache.set).toHaveBeenCalledWith( + 'catalog:component:default/test', + entity, + { ttl: 5000 }, + ); + }); }); diff --git a/plugins/techdocs-backend/src/service/CachedEntityLoader.ts b/plugins/techdocs-backend/src/service/CachedEntityLoader.ts index 7541509907..9f97ed2cd4 100644 --- a/plugins/techdocs-backend/src/service/CachedEntityLoader.ts +++ b/plugins/techdocs-backend/src/service/CachedEntityLoader.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { CacheService } from '@backstage/backend-plugin-api'; +import { + AuthService, + BackstageCredentials, + CacheService, +} from '@backstage/backend-plugin-api'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity, @@ -23,25 +27,29 @@ import { } from '@backstage/catalog-model'; export type CachedEntityLoaderOptions = { + auth: AuthService; catalog: CatalogApi; cache: CacheService; }; export class CachedEntityLoader { + private readonly auth: AuthService; private readonly catalog: CatalogApi; private readonly cache: CacheService; private readonly readTimeout = 1000; - constructor({ catalog, cache }: CachedEntityLoaderOptions) { + constructor({ auth, catalog, cache }: CachedEntityLoaderOptions) { + this.auth = auth; this.catalog = catalog; this.cache = cache; } async load( + credentials: BackstageCredentials, entityRef: CompoundEntityRef, token: string | undefined, ): Promise<Entity | undefined> { - const cacheKey = this.getCacheKey(entityRef, token); + const cacheKey = this.getCacheKey(entityRef, credentials); let result = await this.getFromCache(cacheKey); if (result) { @@ -68,12 +76,14 @@ export class CachedEntityLoader { private getCacheKey( entityName: CompoundEntityRef, - token: string | undefined, + credentials: BackstageCredentials, ): string { const key = ['catalog', stringifyEntityRef(entityName)]; - if (token) { - key.push(token); + if (this.auth.isPrincipal(credentials, 'user')) { + key.push(credentials.principal.userEntityRef); + } else if (this.auth.isPrincipal(credentials, 'service')) { + key.push(credentials.principal.subject); } return key.join(':'); diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index bfaf072717..7ce26232e1 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -124,6 +124,7 @@ export async function createRouter( // Entities are cached to optimize the /static/docs request path, which can be called many times // when loading a single techdocs page. const entityLoader = new CachedEntityLoader({ + auth, catalog: catalogClient, cache: options.cache, }); @@ -158,7 +159,7 @@ export async function createRouter( }); // Verify that the related entity exists and the current user has permission to view it. - const entity = await entityLoader.load(entityName, token); + const entity = await entityLoader.load(credentials, entityName, token); if (!entity) { throw new NotFoundError( @@ -196,7 +197,7 @@ export async function createRouter( targetPluginId: 'catalog', }); - const entity = await entityLoader.load(entityName, token); + const entity = await entityLoader.load(credentials, entityName, token); if (!entity) { throw new NotFoundError( @@ -234,7 +235,11 @@ export async function createRouter( targetPluginId: 'catalog', }); - const entity = await entityLoader.load({ kind, namespace, name }, token); + const entity = await entityLoader.load( + credentials, + { kind, namespace, name }, + token, + ); if (!entity?.metadata?.uid) { throw new NotFoundError('Entity metadata UID missing'); @@ -305,7 +310,7 @@ export async function createRouter( targetPluginId: 'catalog', }); - const entity = await entityLoader.load(entityName, token); + const entity = await entityLoader.load(credentials, entityName, token); if (!entity) { throw new NotFoundError( diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 6cb56e3184..58b1c8b72b 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/plugin-techdocs-react@1.3.2-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + +## 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..c5fd222ff7 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.27-next.0", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index c44b7fca9e..3ffa811697 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-techdocs-node +## 1.13.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/integration-aws-node@0.1.17 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-techdocs-common@0.1.1 + +## 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..e28a87c2f0 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.6-next.0", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-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..0f619cd643 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-techdocs-react +## 1.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/core-plugin-api@1.10.9 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-techdocs-common@0.1.1 + +## 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..c5527dfec1 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.2-next.0", "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..bee5752bfe 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,110 @@ # @backstage/plugin-techdocs +## 1.14.0-next.1 + +### Minor Changes + +- cb0541f: Adds `additionalAllowedURIProtocols` to sanitizer config + +### Patch Changes + +- f2f133c: Internal update to use the new variant of `ApiBlueprint`. +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/catalog-client@1.11.0-next.0 + - @backstage/plugin-search-react@1.9.3-next.0 + - @backstage/plugin-techdocs-react@1.3.2-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/config@1.3.3 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.1 + - @backstage/integration-react@1.2.9 + - @backstage/plugin-auth-react@0.1.18-next.0 + - @backstage/plugin-search-common@1.2.19 + - @backstage/plugin-techdocs-common@0.1.1 + +## 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/config.d.ts b/plugins/techdocs/config.d.ts index bfc98a7927..7294f52816 100644 --- a/plugins/techdocs/config.d.ts +++ b/plugins/techdocs/config.d.ts @@ -58,6 +58,16 @@ export interface Config { * @visibility frontend */ allowedCustomElementAttributeNameRegExp?: string; + /** + * Allows listed protocols in attributes with URI values + * Example: + * additionalAllowedURIProtocols: ['vscode'] + * this will allow all attributes with URI values to have `vscode` protocol like `vscode://some/path` in addition to the default protocols + * matched by DOMPurify's IS_ALLOWED_URI RegExp: + * @see: https://raw.githubusercontent.com/cure53/DOMPurify/master/src/regexp.ts + * @visibility frontend + */ + additionalAllowedURIProtocols?: string; }; }; } diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 40ed4856bf..7bcfc962c9 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.14.0-next.1", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/techdocs/report-alpha.api.md b/plugins/techdocs/report-alpha.api.md index ce1d10a00c..fd63ec1daa 100644 --- a/plugins/techdocs/report-alpha.api.md +++ b/plugins/techdocs/report-alpha.api.md @@ -6,10 +6,12 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiFactory } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha'; import { Entity } from '@backstage/catalog-model'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; +import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -46,9 +48,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'api:techdocs/storage': ExtensionDefinition<{ kind: 'api'; @@ -61,9 +67,13 @@ const _default: FrontendPlugin< {} >; inputs: {}; - params: { - factory: AnyApiFactory; - }; + params: < + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, + >( + params: ApiFactory<TApi, TImpl, TDeps>, + ) => ExtensionBlueprintParams<AnyApiFactory>; }>; 'empty-state:techdocs/entity-content': ExtensionDefinition<{ config: {}; diff --git a/plugins/techdocs/src/alpha/index.tsx b/plugins/techdocs/src/alpha/index.tsx index 44205a480a..38dcd40dc4 100644 --- a/plugins/techdocs/src/alpha/index.tsx +++ b/plugins/techdocs/src/alpha/index.tsx @@ -26,7 +26,6 @@ import { } from '@backstage/frontend-plugin-api'; import { configApiRef, - createApiFactory, discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; @@ -68,8 +67,8 @@ const techdocsEntityIconLink = EntityIconLinkBlueprint.make({ /** @alpha */ const techDocsStorageApi = ApiBlueprint.make({ name: 'storage', - params: { - factory: createApiFactory({ + params: define => + define({ api: techdocsStorageApiRef, deps: { configApi: configApiRef, @@ -83,13 +82,12 @@ const techDocsStorageApi = ApiBlueprint.make({ fetchApi, }), }), - }, }); /** @alpha */ const techDocsClientApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ + params: define => + define({ api: techdocsApiRef, deps: { configApi: configApiRef, @@ -103,7 +101,6 @@ const techDocsClientApi = ApiBlueprint.make({ fetchApi, }), }), - }, }); /** @alpha */ diff --git a/plugins/techdocs/src/reader/transformers/html/transformer.sanitizer.test.tsx b/plugins/techdocs/src/reader/transformers/html/transformer.sanitizer.test.tsx index f79a41a73d..39d3d229aa 100644 --- a/plugins/techdocs/src/reader/transformers/html/transformer.sanitizer.test.tsx +++ b/plugins/techdocs/src/reader/transformers/html/transformer.sanitizer.test.tsx @@ -28,6 +28,7 @@ const configApiMock: ConfigApi = new ConfigReader({ sanitizer: { allowedCustomElementTagNameRegExp: '^backstage-', allowedCustomElementAttributeNameRegExp: 'attribute1|attribute2', + additionalAllowedURIProtocols: ['permitted'], }, }, }); @@ -39,6 +40,28 @@ const wrapper: FC<PropsWithChildren<{}>> = ({ children }) => ( ); describe('Transformers > Html > Sanitizer Custom Elements', () => { + it('allows additional protocols in URIs when provided via config', async () => { + const { result } = renderHook(() => useSanitizerTransformer(), { wrapper }); + const dirtyDom = document.createElement('html'); + + const dirtyHTML = ` + <body> + <a href="permitted:mcp/install">Yep</a> + <a href="nope://not-allowed">Nope</a> + <a href="https://example.com">Example</a> + </body>`; + dirtyDom.innerHTML = dirtyHTML; + + const clearDom = await result.current(dirtyDom); // calling html transformer + const elements = Array.from( + clearDom.querySelectorAll<HTMLAnchorElement>('body > a'), + ); + expect(elements).toHaveLength(3); + expect(elements[0].getAttribute('href')).toEqual('permitted:mcp/install'); + expect(elements[1].getAttribute('href')).toBeNull(); + expect(elements[2].getAttribute('href')).toEqual('https://example.com'); + }); + it('should return a function that allows custom elements matching the pattern in the given dom element', async () => { const { result } = renderHook(() => useSanitizerTransformer(), { wrapper }); diff --git a/plugins/techdocs/src/reader/transformers/html/transformer.ts b/plugins/techdocs/src/reader/transformers/html/transformer.ts index 42f34f0410..7c341c783e 100644 --- a/plugins/techdocs/src/reader/transformers/html/transformer.ts +++ b/plugins/techdocs/src/reader/transformers/html/transformer.ts @@ -78,6 +78,35 @@ export const useSanitizerTransformer = (): Transformer => { const attributeNameCheck = config?.getOptionalString( 'allowedCustomElementAttributeNameRegExp', ); + const additionalAllowedURIProtocols = + config?.getOptionalStringArray('additionalAllowedURIProtocols') || []; + + // Define allowed URI protocols, including any additional ones from the config. + // The default protocols are based on the DOMPurify defaults. + const allowedURIProtocols = [ + 'callto', + 'cid', + 'ftp', + 'ftps', + 'http', + 'https', + 'mailto', + 'matrix', + 'sms', + 'tel', + 'xmpp', + ...additionalAllowedURIProtocols, + ].filter(Boolean); + + const allowedURIRegExp = new RegExp( + // This regex is not exposed by DOMPurify, so we need to define it ourselves. + // It is possible for this to drift from the default in future versions of DOMPurify. + // See: https://raw.githubusercontent.com/cure53/DOMPurify/master/src/regexp.ts + `^(?:${allowedURIProtocols.join( + '|', + )}:|[^a-z]|[a-z+.-]+(?:[^a-z+.\\-:]|$))`, + 'i', + ); // using outerHTML as we want to preserve the html tag attributes (lang) return DOMPurify.sanitize(dom.outerHTML, { @@ -86,6 +115,7 @@ export const useSanitizerTransformer = (): Transformer => { ADD_ATTR: ['http-equiv', 'content', 'dominant-baseline'], WHOLE_DOCUMENT: true, RETURN_DOM: true, + ALLOWED_URI_REGEXP: allowedURIRegExp, CUSTOM_ELEMENT_HANDLING: { tagNameCheck: tagNameCheck ? new RegExp(tagNameCheck) : undefined, attributeNameCheck: attributeNameCheck diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 2139fc3f72..a7a14282f4 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-user-settings-backend +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.2-next.0 + - @backstage/plugin-auth-node@0.6.6-next.0 + - @backstage/backend-plugin-api@1.4.2-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-node@0.1.23-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 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..17158fc0b3 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.5-next.0", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 036af600c6..b7d3104f06 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,93 @@ # @backstage/plugin-user-settings +## 0.8.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.4.5-next.1 + - @backstage/plugin-catalog-react@1.20.0-next.1 + - @backstage/frontend-plugin-api@0.11.0-next.0 + - @backstage/theme@0.6.8-next.0 + - @backstage/core-components@0.17.5-next.0 + - @backstage/catalog-model@1.7.5 + - @backstage/core-app-api@1.18.0 + - @backstage/core-plugin-api@1.10.9 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.15 + - @backstage/plugin-user-settings-common@0.0.1 + +## 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..67a393bac2 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.1", "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/storybook/yarn.lock b/storybook/yarn.lock index d7e83584d1..50401c732b 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -588,14 +588,14 @@ __metadata: languageName: node linkType: hard -"@eslint/config-array@npm:^0.20.0": - version: 0.20.0 - resolution: "@eslint/config-array@npm:0.20.0" +"@eslint/config-array@npm:^0.20.1": + version: 0.20.1 + resolution: "@eslint/config-array@npm:0.20.1" dependencies: "@eslint/object-schema": "npm:^2.1.6" debug: "npm:^4.3.1" minimatch: "npm:^3.1.2" - checksum: 10/9db7f6cbb5363f2f98ee4805ce09d1a95c4349e86f3f456f2c23a0849b7a6aa8d2be4c25e376ee182af062762e15a101844881c89b566eea0856c481ffcb2090 + checksum: 10/d72cc90f516c5730da5f37fa04aa8ba26ea0d92c7457ee77980902158f844f3483518272ccfe16f273c3313c3bfec8da713d4e51d3da49bdeccd34e919a2b903 languageName: node linkType: hard @@ -606,12 +606,21 @@ __metadata: languageName: node linkType: hard -"@eslint/core@npm:^0.13.0": - version: 0.13.0 - resolution: "@eslint/core@npm:0.13.0" +"@eslint/core@npm:^0.14.0": + version: 0.14.0 + resolution: "@eslint/core@npm:0.14.0" dependencies: "@types/json-schema": "npm:^7.0.15" - checksum: 10/737fd1c237405b62592e8daa4b7e25b45ab22108bfec65258cabd091d5717b7c9573acea1f27c4ee7198cefc5a0874f5caefe3d9636851227b1f12d28ef52cf2 + checksum: 10/d9b060cf97468150675ddf4fb3db55edaa32467e0adf9f80919a5bfd15d0835ad7765456f4397ec2d16b0a1bb702af63f6d4712f94194d34fea118231ae1e2db + languageName: node + linkType: hard + +"@eslint/core@npm:^0.15.0": + version: 0.15.0 + resolution: "@eslint/core@npm:0.15.0" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10/27c9cb5bdc5c9dead5b06f2b2a6a66d8bbe5e2e19397e2c5ff9ea582c9d4e4478bf1bc1bdd4eaec7bb3a0d6fa53f152e595acf637354776c14bb58c321ea5aa3 languageName: node linkType: hard @@ -632,10 +641,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.26.0": - version: 9.26.0 - resolution: "@eslint/js@npm:9.26.0" - checksum: 10/863d35df8f6675250bb5a917037e0f6833965437eba4c4649633fd0b55a93e8d727bcd36e9b5cc82047898ee9348cb40363e196f333914ae3a6bb36159495212 +"@eslint/js@npm:9.29.0": + version: 9.29.0 + resolution: "@eslint/js@npm:9.29.0" + checksum: 10/7f7fd586b35bd08537dd65a9bda764f474350c36b4ccbdd342462d1a26be28f7ee0ebd0611dd4762b69829674336ba04c281b9658aeccb3e6ab1d0fec7e6d08c languageName: node linkType: hard @@ -646,13 +655,13 @@ __metadata: languageName: node linkType: hard -"@eslint/plugin-kit@npm:^0.2.8": - version: 0.2.8 - resolution: "@eslint/plugin-kit@npm:0.2.8" +"@eslint/plugin-kit@npm:^0.3.1": + version: 0.3.2 + resolution: "@eslint/plugin-kit@npm:0.3.2" dependencies: - "@eslint/core": "npm:^0.13.0" + "@eslint/core": "npm:^0.15.0" levn: "npm:^0.4.1" - checksum: 10/2e7fe7a88ebdbbf805e9e7265347b7dcfb6bf50beec314def997572b2e8ae4a7b9504fb67b1698a70c348a0dd87251d1e9028292a96fd49b58cb5277d88bdea7 + checksum: 10/26ba99936f72ca124036fbc5ca93168713fab5984117109b1447642a93725fbb75aa457622683dc8797509e40294497d74b584caa26f285373bdde17ceba8eac languageName: node linkType: hard @@ -779,24 +788,6 @@ __metadata: languageName: node linkType: hard -"@modelcontextprotocol/sdk@npm:^1.8.0": - version: 1.11.0 - resolution: "@modelcontextprotocol/sdk@npm:1.11.0" - dependencies: - content-type: "npm:^1.0.5" - cors: "npm:^2.8.5" - cross-spawn: "npm:^7.0.3" - eventsource: "npm:^3.0.2" - express: "npm:^5.0.1" - express-rate-limit: "npm:^7.5.0" - pkce-challenge: "npm:^5.0.0" - raw-body: "npm:^3.0.0" - zod: "npm:^3.23.8" - zod-to-json-schema: "npm:^3.24.1" - checksum: 10/527413fd2b18f75e031cda7f73a662098f3c5f1224b9c6b0b903d5a1f79e23e23a4f4b8e6971bac7eb46a74ed65ae05e8e548f7b7a3f7f6d179c3f6d10825fbc - languageName: node - linkType: hard - "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1884,16 +1875,6 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^2.0.0": - version: 2.0.0 - resolution: "accepts@npm:2.0.0" - dependencies: - mime-types: "npm:^3.0.0" - negotiator: "npm:^1.0.0" - checksum: 10/ea1343992b40b2bfb3a3113fa9c3c2f918ba0f9197ae565c48d3f84d44b174f6b1d5cd9989decd7655963eb03a272abc36968cc439c2907f999bd5ef8653d5a7 - languageName: node - linkType: hard - "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -1903,12 +1884,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.12.1, acorn@npm:^8.14.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" +"acorn@npm:^8.12.1, acorn@npm:^8.15.0": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" bin: acorn: bin/acorn - checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 + checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4 languageName: node linkType: hard @@ -2092,23 +2073,6 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^2.2.0": - version: 2.2.0 - resolution: "body-parser@npm:2.2.0" - dependencies: - bytes: "npm:^3.1.2" - content-type: "npm:^1.0.5" - debug: "npm:^4.4.0" - http-errors: "npm:^2.0.0" - iconv-lite: "npm:^0.6.3" - on-finished: "npm:^2.4.1" - qs: "npm:^6.14.0" - raw-body: "npm:^3.0.0" - type-is: "npm:^2.0.0" - checksum: 10/e9d844b036bd15970df00a16f373c7ed28e1ef870974a0a1d4d6ef60d70e01087cc20a0dbb2081c49a88e3c08ce1d87caf1e2898c615dffa193f63e8faa8a84e - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -2158,13 +2122,6 @@ __metadata: languageName: node linkType: hard -"bytes@npm:3.1.2, bytes@npm:^3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10/a10abf2ba70c784471d6b4f58778c0beeb2b5d405148e66affa91f23a9f13d07603d0a0354667310ae1d6dc141474ffd44e2a074be0f6e2254edb8fc21445388 - languageName: node - linkType: hard - "cacache@npm:^18.0.0": version: 18.0.4 resolution: "cacache@npm:18.0.4" @@ -2208,16 +2165,6 @@ __metadata: languageName: node linkType: hard -"call-bound@npm:^1.0.2": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10/ef2b96e126ec0e58a7ff694db43f4d0d44f80e641370c21549ed911fecbdbc2df3ebc9bddad918d6bbdefeafb60bb3337902006d5176d72bcd2da74820991af7 - languageName: node - linkType: hard - "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -2355,22 +2302,6 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:^1.0.0": - version: 1.0.0 - resolution: "content-disposition@npm:1.0.0" - dependencies: - safe-buffer: "npm:5.2.1" - checksum: 10/0dcc1a2d7874526b0072df3011b134857b49d97a3bc135bb464a299525d4972de6f5f464fd64da6c4d8406d26a1ffb976f62afaffef7723b1021a44498d10e08 - languageName: node - linkType: hard - -"content-type@npm:^1.0.5": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10/585847d98dc7fb8035c02ae2cb76c7a9bd7b25f84c447e5ed55c45c2175e83617c8813871b4ee22f368126af6b2b167df655829007b21aa10302873ea9c62662 - languageName: node - linkType: hard - "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -2378,31 +2309,7 @@ __metadata: languageName: node linkType: hard -"cookie-signature@npm:^1.2.1": - version: 1.2.2 - resolution: "cookie-signature@npm:1.2.2" - checksum: 10/be44a3c9a56f3771aea3a8bd8ad8f0a8e2679bcb967478267f41a510b4eb5ec55085386ba79c706c4ac21605ca76f4251973444b90283e0eb3eeafe8a92c7708 - languageName: node - linkType: hard - -"cookie@npm:^0.7.1": - version: 0.7.2 - resolution: "cookie@npm:0.7.2" - checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f - languageName: node - linkType: hard - -"cors@npm:^2.8.5": - version: 2.8.5 - resolution: "cors@npm:2.8.5" - dependencies: - object-assign: "npm:^4" - vary: "npm:^1" - checksum: 10/66e88e08edee7cbce9d92b4d28a2028c88772a4c73e02f143ed8ca76789f9b59444eed6b1c167139e76fa662998c151322720093ba229f9941365ada5a6fc2c6 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -2427,7 +2334,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.4.0 resolution: "debug@npm:4.4.0" dependencies: @@ -2471,13 +2378,6 @@ __metadata: languageName: node linkType: hard -"depd@npm:2.0.0, depd@npm:^2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10/c0c8ff36079ce5ada64f46cc9d6fd47ebcf38241105b6e0c98f412e8ad91f084bcf906ff644cc3a4bd876ca27a62accb8b0fff72ea6ed1a414b89d8506f4a5ca - languageName: node - linkType: hard - "dequal@npm:^2.0.2, dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -2535,13 +2435,6 @@ __metadata: languageName: node linkType: hard -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10/1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.5.28": version: 1.5.41 resolution: "electron-to-chromium@npm:1.5.41" @@ -2563,13 +2456,6 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:^2.0.0": - version: 2.0.0 - resolution: "encodeurl@npm:2.0.0" - checksum: 10/abf5cd51b78082cf8af7be6785813c33b6df2068ce5191a40ca8b1afe6a86f9230af9a9ce694a5ce4665955e5c1120871826df9c128a642e09c58d592e2807fe - languageName: node - linkType: hard - "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -2812,13 +2698,6 @@ __metadata: languageName: node linkType: hard -"escape-html@npm:^1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10/6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 - languageName: node - linkType: hard - "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -2856,13 +2735,13 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^8.3.0": - version: 8.3.0 - resolution: "eslint-scope@npm:8.3.0" +"eslint-scope@npm:^8.4.0": + version: 8.4.0 + resolution: "eslint-scope@npm:8.4.0" dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" - checksum: 10/ee1ff009e949423639a8b53453c0cb189967d9142c5d94dc3752bed9880140a0760007148ac6b0bd03557d70ede9cd7c3b1e66f9a7f3427b2dbeca2a5be22c91 + checksum: 10/e8e611701f65375e034c62123946e628894f0b54aa8cb11abe224816389abe5cd74cf16b62b72baa36504f22d1a958b9b8b0169b82397fe2e7997674c0d09b06 languageName: node linkType: hard @@ -2873,29 +2752,28 @@ __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 "eslint@npm:^9.11.1": - version: 9.26.0 - resolution: "eslint@npm:9.26.0" + version: 9.29.0 + resolution: "eslint@npm:9.29.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.20.0" + "@eslint/config-array": "npm:^0.20.1" "@eslint/config-helpers": "npm:^0.2.1" - "@eslint/core": "npm:^0.13.0" + "@eslint/core": "npm:^0.14.0" "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.26.0" - "@eslint/plugin-kit": "npm:^0.2.8" + "@eslint/js": "npm:9.29.0" + "@eslint/plugin-kit": "npm:^0.3.1" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" - "@modelcontextprotocol/sdk": "npm:^1.8.0" "@types/estree": "npm:^1.0.6" "@types/json-schema": "npm:^7.0.15" ajv: "npm:^6.12.4" @@ -2903,9 +2781,9 @@ __metadata: cross-spawn: "npm:^7.0.6" debug: "npm:^4.3.2" escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^8.3.0" - eslint-visitor-keys: "npm:^4.2.0" - espree: "npm:^10.3.0" + eslint-scope: "npm:^8.4.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" esquery: "npm:^1.5.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" @@ -2920,7 +2798,6 @@ __metadata: minimatch: "npm:^3.1.2" natural-compare: "npm:^1.4.0" optionator: "npm:^0.9.3" - zod: "npm:^3.24.2" peerDependencies: jiti: "*" peerDependenciesMeta: @@ -2928,18 +2805,18 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/b87092cb7e87f1d0963475c1a1e15e551842ea122925cf13231e742fae565bf3582029a5b0b4aecf793f25c26ee0be3ee1f32190bc361e0c3f3633b9cbace948 + checksum: 10/be0c8e123207c9d653fb75ddc610b85dfbf295a2bfa1cbecc78f191dcba9c421525b5befd5d499ce561eca607c9c33f455e4fff0b1c2d4202c2896dafe95094a languageName: node linkType: hard -"espree@npm:^10.0.1, espree@npm:^10.3.0": - version: 10.3.0 - resolution: "espree@npm:10.3.0" +"espree@npm:^10.0.1, espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" dependencies: - acorn: "npm:^8.14.0" + acorn: "npm:^8.15.0" acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^4.2.0" - checksum: 10/3412d44d4204c9e29d6b5dd0277400cfa0cd68495dc09eae1b9ce79d0c8985c1c5cc09cb9ba32a1cd963f48a49b0c46bdb7736afe395a300aa6bb1c0d86837e8 + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10/9b355b32dbd1cc9f57121d5ee3be258fab87ebeb7c83fc6c02e5af1a74fc8c5ba79fe8c663e69ea112c3e84a1b95e6a2067ac4443ee7813bb85ac7581acb8bf9 languageName: node linkType: hard @@ -3008,29 +2885,6 @@ __metadata: languageName: node linkType: hard -"etag@npm:^1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10/571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff - languageName: node - linkType: hard - -"eventsource-parser@npm:^3.0.1": - version: 3.0.1 - resolution: "eventsource-parser@npm:3.0.1" - checksum: 10/2730c54c3cb47d55d2967f2ece843f9fc95d8a11c2fef6fece8d17d9080193cbe3cd9ac7b04a325977f63cbf8c1664fdd0512dec1aec601666a5c5bd8564b61f - languageName: node - linkType: hard - -"eventsource@npm:^3.0.2": - version: 3.0.6 - resolution: "eventsource@npm:3.0.6" - dependencies: - eventsource-parser: "npm:^3.0.1" - checksum: 10/ac08c7d1b21e454c7685693fe4ace53fc0b84f3cf752699a556876f2a7f33b7a12972ae33d1c407fb920d6d4aed10de52fdf0dd01902ccdf45cd5da8d55e7f88 - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -3038,50 +2892,6 @@ __metadata: languageName: node linkType: hard -"express-rate-limit@npm:^7.5.0": - version: 7.5.0 - resolution: "express-rate-limit@npm:7.5.0" - peerDependencies: - express: ^4.11 || 5 || ^5.0.0-beta.1 - checksum: 10/eff34c83bf586789933a332a339b66649e2cca95c8e977d193aa8bead577d3182ac9f0e9c26f39389287539b8038890ff023f910b54ebb506a26a2ce135b92ca - languageName: node - linkType: hard - -"express@npm:^5.0.1": - version: 5.1.0 - resolution: "express@npm:5.1.0" - dependencies: - accepts: "npm:^2.0.0" - body-parser: "npm:^2.2.0" - content-disposition: "npm:^1.0.0" - content-type: "npm:^1.0.5" - cookie: "npm:^0.7.1" - cookie-signature: "npm:^1.2.1" - debug: "npm:^4.4.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - finalhandler: "npm:^2.1.0" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.0" - merge-descriptors: "npm:^2.0.0" - mime-types: "npm:^3.0.0" - on-finished: "npm:^2.4.1" - once: "npm:^1.4.0" - parseurl: "npm:^1.3.3" - proxy-addr: "npm:^2.0.7" - qs: "npm:^6.14.0" - range-parser: "npm:^1.2.1" - router: "npm:^2.2.0" - send: "npm:^1.1.0" - serve-static: "npm:^2.2.0" - statuses: "npm:^2.0.1" - type-is: "npm:^2.0.1" - vary: "npm:^1.1.2" - checksum: 10/6dba00bbdf308f43a84ed3f07a7e9870d5208f2a0b8f60f39459dda089750379747819863fad250849d3c9163833f33f94ce69d73938df31e0c5a430800d7e56 - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -3150,20 +2960,6 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:^2.1.0": - version: 2.1.0 - resolution: "finalhandler@npm:2.1.0" - dependencies: - debug: "npm:^4.4.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - on-finished: "npm:^2.4.1" - parseurl: "npm:^1.3.3" - statuses: "npm:^2.0.1" - checksum: 10/b2bd68c310e2c463df0ab747ab05f8defbc540b8c3f2442f86e7d084ac8acbc31f8cae079931b7f5a406521501941e3395e963de848a0aaf45dd414adeb5ff4e - languageName: node - linkType: hard - "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -3210,20 +3006,6 @@ __metadata: languageName: node linkType: hard -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10/29ba9fd347117144e97cbb8852baae5e8b2acb7d1b591ef85695ed96f5b933b1804a7fac4a15dd09ca7ac7d0cdc104410e8102aae2dd3faa570a797ba07adb81 - languageName: node - linkType: hard - -"fresh@npm:^2.0.0": - version: 2.0.0 - resolution: "fresh@npm:2.0.0" - checksum: 10/44e1468488363074641991c1340d2a10c5a6f6d7c353d89fd161c49d120c58ebf9890720f7584f509058385836e3ce50ddb60e9f017315a4ba8c6c3461813bfc - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -3275,7 +3057,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.3.0": +"get-intrinsic@npm:^1.2.4": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" dependencies: @@ -3448,19 +3230,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:2.0.0, http-errors@npm:^2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: "npm:2.0.0" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - toidentifier: "npm:1.0.1" - checksum: 10/0e7f76ee8ff8a33e58a3281a469815b893c41357378f408be8f6d4aa7d1efafb0da064625518e7078381b6a92325949b119dc38fcb30bdbc4e3a35f78c44c439 - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -3481,7 +3250,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": +"iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -3521,7 +3290,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2.0.4, inherits@npm:^2.0.3": +"inherits@npm:^2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 @@ -3538,13 +3307,6 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10/864d0cced0c0832700e9621913a6429ccdc67f37c1bd78fb8c6789fff35c9d167cb329134acad2290497a53336813ab4798d2794fd675d5eb33b5fdf0982b9ca - languageName: node - linkType: hard - "is-arguments@npm:^1.0.4": version: 1.1.1 resolution: "is-arguments@npm:1.1.1" @@ -3626,13 +3388,6 @@ __metadata: languageName: node linkType: hard -"is-promise@npm:^4.0.0": - version: 4.0.0 - resolution: "is-promise@npm:4.0.0" - checksum: 10/0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a - languageName: node - linkType: hard - "is-typed-array@npm:^1.1.3": version: 1.1.13 resolution: "is-typed-array@npm:1.1.13" @@ -3899,13 +3654,6 @@ __metadata: languageName: node linkType: hard -"media-typer@npm:^1.1.0": - version: 1.1.0 - resolution: "media-typer@npm:1.1.0" - checksum: 10/a58dd60804df73c672942a7253ccc06815612326dc1c0827984b1a21704466d7cde351394f47649e56cf7415e6ee2e26e000e81b51b3eebb5a93540e8bf93cbd - languageName: node - linkType: hard - "memoizerific@npm:^1.11.3": version: 1.11.3 resolution: "memoizerific@npm:1.11.3" @@ -3915,13 +3663,6 @@ __metadata: languageName: node linkType: hard -"merge-descriptors@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-descriptors@npm:2.0.0" - checksum: 10/e383332e700a94682d0125a36c8be761142a1320fc9feeb18e6e36647c9edf064271645f5669b2c21cf352116e561914fd8aa831b651f34db15ef4038c86696a - languageName: node - linkType: hard - "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" @@ -3939,22 +3680,6 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:^1.54.0": - version: 1.54.0 - resolution: "mime-db@npm:1.54.0" - checksum: 10/9e7834be3d66ae7f10eaa69215732c6d389692b194f876198dca79b2b90cbf96688d9d5d05ef7987b20f749b769b11c01766564264ea5f919c88b32a29011311 - languageName: node - linkType: hard - -"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1": - version: 3.0.1 - resolution: "mime-types@npm:3.0.1" - dependencies: - mime-db: "npm:^1.54.0" - checksum: 10/fa1d3a928363723a8046c346d87bf85d35014dae4285ad70a3ff92bd35957992b3094f8417973cfe677330916c6ef30885109624f1fb3b1e61a78af509dba120 - languageName: node - linkType: hard - "min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" @@ -4117,13 +3842,6 @@ __metadata: languageName: node linkType: hard -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 - languageName: node - linkType: hard - "node-gyp@npm:latest": version: 10.2.0 resolution: "node-gyp@npm:10.2.0" @@ -4162,38 +3880,6 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10/fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb - languageName: node - linkType: hard - -"on-finished@npm:^2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10/8e81472c5028125c8c39044ac4ab8ba51a7cdc19a9fbd4710f5d524a74c6d8c9ded4dd0eed83f28d3d33ac1d7a6a439ba948ccb765ac6ce87f30450a26bfe2ea - languageName: node - linkType: hard - -"once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - "open@npm:^8.0.4": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -4262,13 +3948,6 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10/407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 - languageName: node - linkType: hard - "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -4300,13 +3979,6 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:^8.0.0": - version: 8.2.0 - resolution: "path-to-regexp@npm:8.2.0" - checksum: 10/23378276a172b8ba5f5fb824475d1818ca5ccee7bbdb4674701616470f23a14e536c1db11da9c9e6d82b82c556a817bbf4eee6e41b9ed20090ef9427cbb38e13 - languageName: node - linkType: hard - "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -4335,13 +4007,6 @@ __metadata: languageName: node linkType: hard -"pkce-challenge@npm:^5.0.0": - version: 5.0.0 - resolution: "pkce-challenge@npm:5.0.0" - checksum: 10/e60c06a0e0481cb82f80072053d5c479a7490758541c4226460450285dd5d72a995c44b3c553731ca7c2f64cc34b35f1d2e5f9de08d276b59899298f9efe1ddf - languageName: node - linkType: hard - "polished@npm:^4.2.2": version: 4.3.1 resolution: "polished@npm:4.3.1" @@ -4420,16 +4085,6 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:^2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10/f24a0c80af0e75d31e3451398670d73406ec642914da11a2965b80b1898ca6f66a0e3e091a11a4327079b2b268795f6fa06691923fef91887215c3d0e8ea3f68 - languageName: node - linkType: hard - "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -4437,15 +4092,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.14.0": - version: 6.14.0 - resolution: "qs@npm:6.14.0" - dependencies: - side-channel: "npm:^1.1.0" - checksum: 10/a60e49bbd51c935a8a4759e7505677b122e23bf392d6535b8fc31c1e447acba2c901235ecb192764013cd2781723dc1f61978b5fdd93cc31d7043d31cdc01974 - languageName: node - linkType: hard - "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -4453,25 +4099,6 @@ __metadata: languageName: node linkType: hard -"range-parser@npm:^1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 10/ce21ef2a2dd40506893157970dc76e835c78cf56437e26e19189c48d5291e7279314477b06ac38abd6a401b661a6840f7b03bd0b1249da9b691deeaa15872c26 - languageName: node - linkType: hard - -"raw-body@npm:^3.0.0": - version: 3.0.0 - resolution: "raw-body@npm:3.0.0" - dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.6.3" - unpipe: "npm:1.0.0" - checksum: 10/2443429bbb2f9ae5c50d3d2a6c342533dfbde6b3173740b70fa0302b30914ff400c6d31a46b3ceacbe7d0925dc07d4413928278b494b04a65736fc17ca33e30c - languageName: node - linkType: hard - "react-confetti@npm:^6.1.0": version: 6.1.0 resolution: "react-confetti@npm:6.1.0" @@ -4720,19 +4347,6 @@ __metadata: languageName: node linkType: hard -"router@npm:^2.2.0": - version: 2.2.0 - resolution: "router@npm:2.2.0" - dependencies: - debug: "npm:^4.4.0" - depd: "npm:^2.0.0" - is-promise: "npm:^4.0.0" - parseurl: "npm:^1.3.3" - path-to-regexp: "npm:^8.0.0" - checksum: 10/8949bd1d3da5403cc024e2989fee58d7fda0f3ffe9f2dc5b8a192f295f400b3cde307b0b554f7d44851077640f36962ca469a766b3d57410d7d96245a7ba6c91 - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -4742,13 +4356,6 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 - languageName: node - linkType: hard - "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -4790,37 +4397,6 @@ __metadata: languageName: node linkType: hard -"send@npm:^1.1.0, send@npm:^1.2.0": - version: 1.2.0 - resolution: "send@npm:1.2.0" - dependencies: - debug: "npm:^4.3.5" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.0" - mime-types: "npm:^3.0.1" - ms: "npm:^2.1.3" - on-finished: "npm:^2.4.1" - range-parser: "npm:^1.2.1" - statuses: "npm:^2.0.1" - checksum: 10/9fa3b1a3b9a06b7b4ab00c25e8228326d9665a9745753a34d1ffab8ac63c7c206727331d1dc5be73647f1b658d259a1aa8e275b0e0eee51349370af02e9da506 - languageName: node - linkType: hard - -"serve-static@npm:^2.2.0": - version: 2.2.0 - resolution: "serve-static@npm:2.2.0" - dependencies: - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - parseurl: "npm:^1.3.3" - send: "npm:^1.2.0" - checksum: 10/9f1a900738c5bb02258275ce3bd1273379c4c3072b622e15d44e8f47d89a1ba2d639ec2d63b11c263ca936096b40758acb7a0d989cd6989018a65a12f9433ada - languageName: node - linkType: hard - "set-function-length@npm:^1.2.1": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" @@ -4835,13 +4411,6 @@ __metadata: languageName: node linkType: hard -"setprototypeof@npm:1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10/fde1630422502fbbc19e6844346778f99d449986b2f9cdcceb8326730d2f3d9964dbcb03c02aaadaefffecd0f2c063315ebea8b3ad895914bf1afc1747fc172e - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -4858,54 +4427,6 @@ __metadata: languageName: node linkType: hard -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10/603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba - languageName: node - linkType: hard - "signal-exit@npm:^4.0.1": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -4978,13 +4499,6 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1, statuses@npm:^2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 10/18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb - languageName: node - linkType: hard - "storybook@npm:^8.3.5": version: 8.6.12 resolution: "storybook@npm:8.6.12" @@ -5151,13 +4665,6 @@ __metadata: languageName: node linkType: hard -"toidentifier@npm:1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10/952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 - languageName: node - linkType: hard - "ts-api-utils@npm:^2.0.1": version: 2.0.1 resolution: "ts-api-utils@npm:2.0.1" @@ -5233,17 +4740,6 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^2.0.0, type-is@npm:^2.0.1": - version: 2.0.1 - resolution: "type-is@npm:2.0.1" - dependencies: - content-type: "npm:^1.0.5" - media-typer: "npm:^1.1.0" - mime-types: "npm:^3.0.0" - checksum: 10/bacdb23c872dacb7bd40fbd9095e6b2fca2895eedbb689160c05534d7d4810a7f4b3fd1ae87e96133c505958f6d602967a68db5ff577b85dd6be76eaa75d58af - languageName: node - linkType: hard - "typescript-eslint@npm:^8.7.0": version: 8.26.0 resolution: "typescript-eslint@npm:8.26.0" @@ -5303,13 +4799,6 @@ __metadata: languageName: node linkType: hard -"unpipe@npm:1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10/4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 - languageName: node - linkType: hard - "unplugin@npm:^1.3.1": version: 1.14.1 resolution: "unplugin@npm:1.14.1" @@ -5370,13 +4859,6 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:^1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10/31389debef15a480849b8331b220782230b9815a8e0dbb7b9a8369559aed2e9a7800cd904d4371ea74f4c3527db456dc8e7ac5befce5f0d289014dbdf47b2242 - languageName: node - linkType: hard - "vite@npm:^5.4.8": version: 5.4.19 resolution: "vite@npm:5.4.19" @@ -5491,13 +4973,6 @@ __metadata: languageName: node linkType: hard -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - "ws@npm:^8.2.3": version: 8.18.0 resolution: "ws@npm:8.18.0" @@ -5533,19 +5008,3 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"zod-to-json-schema@npm:^3.24.1": - version: 3.24.5 - resolution: "zod-to-json-schema@npm:3.24.5" - peerDependencies: - zod: ^3.24.1 - checksum: 10/1af291b4c429945c9568c2e924bdb7c66ab8d139cbeb9a99b6e9fc9e1b02863f85d07759b9303714f07ceda3993dcaf0ebcb80d2c18bb2aaf5502b2c1016affd - languageName: node - linkType: hard - -"zod@npm:^3.23.8, zod@npm:^3.24.2": - version: 3.24.4 - resolution: "zod@npm:3.24.4" - checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 - languageName: node - linkType: hard diff --git a/yarn.lock b/yarn.lock index c3e37b0ac0..93efffc60f 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" @@ -3594,7 +3555,7 @@ __metadata: archiver: "npm:^7.0.0" aws-sdk-client-mock: "npm:^4.0.0" base64-stream: "npm:^1.0.0" - better-sqlite3: "npm:^11.0.0" + better-sqlite3: "npm:^12.0.0" compression: "npm:^1.7.4" concat-stream: "npm:^2.0.0" cookie: "npm:^0.7.0" @@ -3724,7 +3685,29 @@ __metadata: languageName: unknown linkType: soft -"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.1.1, @backstage/backend-plugin-api@workspace:^, @backstage/backend-plugin-api@workspace:packages/backend-plugin-api": +"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.1.1, @backstage/backend-plugin-api@npm:^1.4.1": + version: 1.4.1 + resolution: "@backstage/backend-plugin-api@npm:1.4.1" + dependencies: + "@backstage/cli-common": "npm:^0.1.15" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/plugin-auth-node": "npm:^0.6.5" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/plugin-permission-node": "npm:^0.10.2" + "@backstage/types": "npm:^1.2.1" + "@types/express": "npm:^4.17.6" + "@types/json-schema": "npm:^7.0.6" + "@types/luxon": "npm:^3.0.0" + json-schema: "npm:^0.4.0" + knex: "npm:^3.0.0" + luxon: "npm:^3.0.0" + zod: "npm:^3.22.4" + checksum: 10/4660bd6e0bdb48257ab058e9709a41ec0484d7c81078d978b45b89793e91f2a5849b6b53efc5b2a588f7ae34099928d75bfc75b72abbda69dd006eb264092f05 + languageName: node + linkType: hard + +"@backstage/backend-plugin-api@workspace:^, @backstage/backend-plugin-api@workspace:packages/backend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/backend-plugin-api@workspace:packages/backend-plugin-api" dependencies: @@ -3770,7 +3753,7 @@ __metadata: "@types/keyv": "npm:^4.2.0" "@types/qs": "npm:^6.9.6" "@types/supertest": "npm:^2.0.8" - better-sqlite3: "npm:^11.0.0" + better-sqlite3: "npm:^12.0.0" cookie: "npm:^0.7.0" express: "npm:^4.17.1" fs-extra: "npm:^11.0.0" @@ -3789,62 +3772,42 @@ __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 -"@backstage/catalog-client@npm:^1.9.1, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@npm:^1.10.2, @backstage/catalog-client@npm:^1.9.1": + version: 1.10.2 + resolution: "@backstage/catalog-client@npm:1.10.2" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/errors": "npm:^1.2.7" + cross-fetch: "npm:^4.0.0" + uri-template: "npm:^2.0.0" + checksum: 10/06a300df1bed6e2933e15342474a3027c258e7523052dd2f0e52faa4d5b720b40c11cc6dd70e7c273357449c0a2177e3ba7ce8c5fa6fd69952a72b417c05914b + languageName: node + linkType: hard + +"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" cross-fetch: "npm:^4.0.0" msw: "npm:^1.0.0" uri-template: "npm:^2.0.0" 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@npm:^1.7.5, @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: @@ -3859,7 +3822,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@workspace:^, @backstage/cli-common@workspace:packages/cli-common": +"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@npm:^0.1.15, @backstage/cli-common@workspace:^, @backstage/cli-common@workspace:packages/cli-common": version: 0.0.0-use.local resolution: "@backstage/cli-common@workspace:packages/cli-common" dependencies: @@ -4101,7 +4064,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@npm:^1.3.3, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -4161,8 +4124,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 +4135,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 +4154,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 +4232,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 +4343,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 +4543,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 +4574,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: @@ -5365,6 +5222,29 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-auth-node@npm:^0.6.5": + version: 0.6.5 + resolution: "@backstage/plugin-auth-node@npm:0.6.5" + dependencies: + "@backstage/backend-plugin-api": "npm:^1.4.1" + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.1" + "@types/express": "npm:^4.17.6" + "@types/passport": "npm:^1.0.3" + express: "npm:^4.17.1" + jose: "npm:^5.0.0" + lodash: "npm:^4.17.21" + passport: "npm:^0.7.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.21.4" + zod-validation-error: "npm:^3.4.0" + checksum: 10/0518d9e245aa6060db8178a51a23de064f5d2fe7cd0e8336db904767159e75992ac5185ee1f07a9664628fb172f9e3db5fdb1255c63f24bbcc449d308b7d3d84 + languageName: node + linkType: hard + "@backstage/plugin-auth-node@workspace:^, @backstage/plugin-auth-node@workspace:plugins/auth-node": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-node@workspace:plugins/auth-node" @@ -5864,7 +5744,6 @@ __metadata: "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" "@backstage/repo-tools": "workspace:^" - "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" "@opentelemetry/api": "npm:^1.9.0" "@types/core-js": "npm:^2.5.4" @@ -5873,7 +5752,7 @@ __metadata: "@types/glob": "npm:^8.0.0" "@types/lodash": "npm:^4.14.151" "@types/supertest": "npm:^2.0.8" - better-sqlite3: "npm:^11.0.0" + better-sqlite3: "npm:^12.0.0" codeowners-utils: "npm:^1.0.2" core-js: "npm:^3.6.5" express: "npm:^4.17.1" @@ -5898,7 +5777,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: @@ -6024,7 +5903,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: @@ -7108,7 +6987,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@npm:^0.9.1, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -7124,6 +7003,24 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-permission-node@npm:^0.10.2": + version: 0.10.2 + resolution: "@backstage/plugin-permission-node@npm:0.10.2" + dependencies: + "@backstage/backend-plugin-api": "npm:^1.4.1" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/plugin-auth-node": "npm:^0.6.5" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@types/express": "npm:^4.17.6" + express: "npm:^4.17.1" + express-promise-router: "npm:^4.1.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.20.4" + checksum: 10/6a5addb61caf5f7fa92169e4e122b7c861db42141a7eb254ea933780679d1ccc0d9e3ea2f6131ef11f20ddac3347f1b485a715667ecb7de1cc8651a44f2f8d7d + languageName: node + linkType: hard + "@backstage/plugin-permission-node@workspace:^, @backstage/plugin-permission-node@workspace:plugins/permission-node": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-node@workspace:plugins/permission-node" @@ -7500,8 +7397,8 @@ __metadata: resolution: "@backstage/plugin-scaffolder-backend@workspace:plugins/scaffolder-backend" dependencies: "@backstage/backend-app-api": "workspace:^" - "@backstage/backend-common": "npm:^0.25.0" "@backstage/backend-defaults": "workspace:^" + "@backstage/backend-openapi-utils": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-model": "workspace:^" @@ -7527,6 +7424,7 @@ __metadata: "@backstage/plugin-scaffolder-common": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" + "@backstage/repo-tools": "workspace:^" "@backstage/types": "workspace:^" "@opentelemetry/api": "npm:^1.9.0" "@types/express": "npm:^4.17.6" @@ -7538,7 +7436,6 @@ __metadata: concat-stream: "npm:^2.0.0" esbuild: "npm:^0.25.0" express: "npm:^4.17.1" - express-promise-router: "npm:^4.1.0" fs-extra: "npm:^11.2.0" globby: "npm:^11.0.0" isbinaryfile: "npm:^5.0.0" @@ -7573,8 +7470,18 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" + "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" + "@microsoft/fetch-event-source": "npm:^2.0.1" + "@types/json-schema": "npm:^7.0.9" + cross-fetch: "npm:^4.0.0" + json-schema: "npm:^0.4.0" + msw: "npm:^1.0.0" + uri-template: "npm:^2.0.0" + zen-observable: "npm:^0.10.0" languageName: unknown linkType: soft @@ -7615,6 +7522,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" @@ -7733,7 +7641,6 @@ __metadata: "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" - "@microsoft/fetch-event-source": "npm:^2.0.1" "@react-hookz/web": "npm:^24.0.0" "@rjsf/core": "npm:5.23.2" "@rjsf/material-ui": "npm:5.23.2" @@ -7758,7 +7665,6 @@ __metadata: jszip: "npm:^3.10.1" lodash: "npm:^4.17.21" luxon: "npm:^3.0.0" - msw: "npm:^1.0.0" qs: "npm:^6.9.4" react: "npm:^18.0.2" react-dom: "npm:^18.0.2" @@ -7768,7 +7674,6 @@ __metadata: react-window: "npm:^1.8.10" swr: "npm:^2.0.0" yaml: "npm:^2.0.0" - zen-observable: "npm:^0.10.0" zod: "npm:^3.22.4" zod-to-json-schema: "npm:^3.20.4" peerDependencies: @@ -8115,6 +8020,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:^" @@ -8591,23 +8497,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: @@ -8645,7 +8535,51 @@ __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" + "@gsap/react": "npm:^2.1.2" + "@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" + concurrently: "npm:^9.2.0" + eslint-plugin-storybook: "npm:^0.12.0" + glob: "npm:^11.0.1" + globals: "npm:^15.11.0" + gsap: "npm:^3.13.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 + 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: @@ -8758,9 +8692,9 @@ __metadata: languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^6.0.8": - version: 6.0.8 - resolution: "@changesets/assemble-release-plan@npm:6.0.8" +"@changesets/assemble-release-plan@npm:^6.0.9": + version: 6.0.9 + resolution: "@changesets/assemble-release-plan@npm:6.0.9" dependencies: "@changesets/errors": "npm:^0.2.0" "@changesets/get-dependents-graph": "npm:^2.1.3" @@ -8768,7 +8702,7 @@ __metadata: "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" semver: "npm:^7.5.3" - checksum: 10/5d01fc42c67229874cc70b93fbdc971e11909aa7a72f1909c585ecb3fdc69f3ac105d243e1341cd5b07c02dee133be461fa48138125f00d137e71f8b7e8f428e + checksum: 10/f84656eabb700ed77f97751b282e1701636ed45a44b443abd9af0291870495cc046fee301478010f39a1dc455799065ae007b9d7d2bb5ae8b793b65bbb8e052a languageName: node linkType: hard @@ -8782,16 +8716,16 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.29.4 - resolution: "@changesets/cli@npm:2.29.4" + version: 2.29.5 + resolution: "@changesets/cli@npm:2.29.5" dependencies: "@changesets/apply-release-plan": "npm:^7.0.12" - "@changesets/assemble-release-plan": "npm:^6.0.8" + "@changesets/assemble-release-plan": "npm:^6.0.9" "@changesets/changelog-git": "npm:^0.2.1" "@changesets/config": "npm:^3.1.1" "@changesets/errors": "npm:^0.2.0" "@changesets/get-dependents-graph": "npm:^2.1.3" - "@changesets/get-release-plan": "npm:^4.0.12" + "@changesets/get-release-plan": "npm:^4.0.13" "@changesets/git": "npm:^3.0.4" "@changesets/logger": "npm:^0.1.1" "@changesets/pre": "npm:^2.0.2" @@ -8815,7 +8749,7 @@ __metadata: term-size: "npm:^2.1.0" bin: changeset: bin.js - checksum: 10/fc325447b81a811464107e72a687f6c0414c5f928e518cb122d1efde1d71c205b1972464795ab97fb26087900ea55b99a551e9a010c9681def3d7561fd1c3f0b + checksum: 10/f401da29025d7bcc07b732bb09a9627f785bfc21c7c2005861d11ffea732bc14d33394fc2fcae50cc5f2b710f6080c5babe2fa90d432de5fdb47ae6afc147936 languageName: node linkType: hard @@ -8855,17 +8789,17 @@ __metadata: languageName: node linkType: hard -"@changesets/get-release-plan@npm:^4.0.12": - version: 4.0.12 - resolution: "@changesets/get-release-plan@npm:4.0.12" +"@changesets/get-release-plan@npm:^4.0.13": + version: 4.0.13 + resolution: "@changesets/get-release-plan@npm:4.0.13" dependencies: - "@changesets/assemble-release-plan": "npm:^6.0.8" + "@changesets/assemble-release-plan": "npm:^6.0.9" "@changesets/config": "npm:^3.1.1" "@changesets/pre": "npm:^2.0.2" "@changesets/read": "npm:^0.6.5" "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" - checksum: 10/d6482ecb6f1c2c47266493a36d05b484f0950d0a4472820649e953d073e3fdd612cdd8a4df9e3d7e00756d4e446dae639f9d6e0dab8a25f76bb6df77cd91c21c + checksum: 10/9983fae5a68012c4c418ddd62f2fb3d325363f21160252ff7b868503a1a2effb8fdd32e4a0289b72653afc3605ce19d163ff69205c942a0004efb571a5f78fd0 languageName: node linkType: hard @@ -9001,8 +8935,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.11.1 - resolution: "@codemirror/language@npm:6.11.1" + version: 6.11.2 + resolution: "@codemirror/language@npm:6.11.2" dependencies: "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.23.0" @@ -9010,7 +8944,7 @@ __metadata: "@lezer/highlight": "npm:^1.0.0" "@lezer/lr": "npm:^1.0.0" style-mod: "npm:^4.0.0" - checksum: 10/024969113d61ccb5d497b75a8a9875d43e1bfc8466de2819bb5db23f01b200937366800a812e8d33eb5e34e3a5d2aa22d0ff8205f34a5e8aeb4cd1d221bcaa78 + checksum: 10/6ecccc48ad4390fca94525eefd0f4c904effad285e1d1de0db3764f08fd33299e5e453ab4d9ff8c33b4baeeb95f4a78660152ab64255fd19eccd31142410f6ed languageName: node linkType: hard @@ -9067,14 +9001,14 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.37.2 - resolution: "@codemirror/view@npm:6.37.2" + version: 6.38.1 + resolution: "@codemirror/view@npm:6.38.1" dependencies: "@codemirror/state": "npm:^6.5.0" crelt: "npm:^1.0.6" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/410ef68c5bd3395c556f5a1298afd6a37eecd88b825435dc19ce7143b0eb5c4114486b444e56fd156371fcc329ad9425635c0703322384ff582a75a4d61727a7 + checksum: 10/e0c5a365608749dd096ba7a930c8393f316bf4c2cacd1465a47a057d0a9f9868ff372a0bb6eb696c926f88411139f79a97a05f8c884bcc380145445cc61e68c8 languageName: node linkType: hard @@ -9106,11 +9040,11 @@ __metadata: linkType: hard "@dagrejs/dagre@npm:^1.1.4": - version: 1.1.4 - resolution: "@dagrejs/dagre@npm:1.1.4" + version: 1.1.5 + resolution: "@dagrejs/dagre@npm:1.1.5" dependencies: "@dagrejs/graphlib": "npm:2.2.4" - checksum: 10/0b3744b170c68ae0666e03aca19c3100d5131feafeb54b3ea096b749a9f0fe5385b8bd8889c11a49493cfab945b2486b9e30bc41b321755ed718e9f5cb4b74f1 + checksum: 10/c00abd1e04d19f90ad8dfa0a4e16365371bc4309affead3827a1b39f6b0b946643b8af0b1e5519011deca3fda4c7471b27e9ebb03423309a94f95ac0b881ac4f languageName: node linkType: hard @@ -9151,6 +9085,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" @@ -9880,16 +9824,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 @@ -9960,14 +9904,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 @@ -10069,12 +10013,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 @@ -10456,6 +10400,16 @@ __metadata: languageName: node linkType: hard +"@gsap/react@npm:^2.1.2": + version: 2.1.2 + resolution: "@gsap/react@npm:2.1.2" + peerDependencies: + gsap: ^3.12.5 + react: ">=17" + checksum: 10/48e78bbb31a4ec5a75aab6ea69ec3f4df0bb7cff0c8ebfcdc14553cb8e35f54b7fcf94f933e2aa65fd977135aaac87b855007d376504f1bb93a74328ba1dc0cb + languageName: node + linkType: hard + "@headlessui/react@npm:^1.7.15": version: 1.7.17 resolution: "@headlessui/react@npm:1.7.17" @@ -11253,14 +11207,14 @@ __metadata: linkType: hard "@keyv/redis@npm:^4.0.1": - version: 4.4.0 - resolution: "@keyv/redis@npm:4.4.0" + version: 4.4.1 + resolution: "@keyv/redis@npm:4.4.1" dependencies: "@redis/client": "npm:^1.6.0" cluster-key-slot: "npm:^1.1.2" peerDependencies: - keyv: ^5.3.3 - checksum: 10/61ad0a026f1ee8bbd0f09bb1b3c731619b37dc4bba0d5f2111cb5249e643e6a776816786090c53d5ac1fa62a43e1b43d406dae06cfb119abcb47b6ac837eebb0 + keyv: ^5.3.4 + checksum: 10/85bf5830d5a19f45fbba864f7eb830cff0059f3f7c59c711a65b439821008a3321a94fb06c4d1f09295f0f233422586458652d266696c0925b5c8d1d695700ec languageName: node linkType: hard @@ -11274,11 +11228,11 @@ __metadata: linkType: hard "@keyv/valkey@npm:^1.0.1": - version: 1.0.4 - resolution: "@keyv/valkey@npm:1.0.4" + version: 1.0.6 + resolution: "@keyv/valkey@npm:1.0.6" dependencies: - iovalkey: "npm:^0.3.1" - checksum: 10/93362c51c14bb8e515a9af8df4a22e028fcec5a09931eb68f854698676cb16cecad691330c75c1dca8b6a986a4763cac9f1b2fd4e5b8216f06648d9379f55cc6 + iovalkey: "npm:^0.3.3" + checksum: 10/36e48930928845e6a14dfb4f9f8069851ff10d3aeef62277f78c8dcea735f8dca5faf4399f67fc2730231b24270d9ab6be77a46e122e9006d3f6e55cc5c0b97a languageName: node linkType: hard @@ -11508,7 +11462,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: @@ -11771,8 +11725,8 @@ __metadata: linkType: hard "@modelcontextprotocol/sdk@npm:^1.12.3": - version: 1.12.3 - resolution: "@modelcontextprotocol/sdk@npm:1.12.3" + version: 1.13.1 + resolution: "@modelcontextprotocol/sdk@npm:1.13.1" dependencies: ajv: "npm:^6.12.6" content-type: "npm:^1.0.5" @@ -11785,7 +11739,7 @@ __metadata: raw-body: "npm:^3.0.0" zod: "npm:^3.23.8" zod-to-json-schema: "npm:^3.24.1" - checksum: 10/abab9b3fcce45370aadc260e9f02587308455ea907cf58b5e7f2e27c0ef4d19bf591f80284592b69f3d1656e4b362b2a96788eb1492daa3e7e2129c49b3eea98 + checksum: 10/b516d72e1cd14c67c8a2e5cb95fcc1c03c50be989850e3e963a7ed11000acb604e65efeaad47ea93c847130536ee51859a8d34e6dbe99d408e1a24224592e57f languageName: node linkType: hard @@ -12345,11 +12299,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" @@ -12364,13 +12318,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" @@ -12392,7 +12346,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 10/88f8a3c52a98c059e6d93c5faf9194daee4667b1a855f88233582acf51e3be9aedb3e3f7f992da46e0e45df31ad4e045e0296e6e35ea14e2245d4069176711c0 + checksum: 10/b46a9f877170f7e96429da5970684525277bcb341f3a24032b6748ad503b5c7164b77410daf9c0f3ca99b5f6b99985d5eb739501cfc01c941218397f32f2d095 languageName: node linkType: hard @@ -13457,12 +13411,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" @@ -13471,7 +13425,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" @@ -13480,7 +13434,7 @@ __metadata: tslib: "npm:2.8.1" bin: openapi-generator-cli: main.js - checksum: 10/29807b52555e7307207eff6e0c4c1a25b970252915e13d847a6c275d1d638af0732761e51816f5bb5a91830ebabc044b3924a106db8cffa19dda01517a77be17 + checksum: 10/76e40b238074c8bf09c99c70222cd80aa1d8be8b9abe6c400542f1bd46c3058238247085835a08a57bb0a43dceeff40b3cb8c4ea736692d040c1d29c48bd1db7 languageName: node linkType: hard @@ -13498,6 +13452,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" @@ -13507,15 +13470,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" @@ -13523,60 +13477,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 @@ -13589,12 +13545,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 @@ -13609,18 +13565,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: @@ -13631,6 +13587,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" @@ -13646,18 +13618,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 @@ -13676,18 +13648,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 @@ -13708,20 +13682,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 @@ -13738,6 +13757,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" @@ -13754,19 +13790,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 @@ -13785,18 +13820,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 @@ -13815,21 +13850,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" @@ -13844,508 +13864,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 @@ -14365,19 +14408,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 @@ -14393,15 +14432,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 @@ -14419,17 +14460,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 @@ -14450,29 +14494,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 @@ -14487,14 +14514,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 @@ -14509,87 +14536,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 @@ -14605,27 +14632,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 @@ -14642,19 +14670,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" @@ -14667,15 +14682,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 @@ -14705,32 +14752,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" @@ -14744,16 +14765,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 @@ -14773,19 +14794,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 @@ -14803,49 +14821,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 @@ -14866,13 +14863,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.53.0 - resolution: "@playwright/test@npm:1.53.0" + version: 1.53.2 + resolution: "@playwright/test@npm:1.53.2" dependencies: - playwright: "npm:1.53.0" + playwright: "npm:1.53.2" bin: playwright: cli.js - checksum: 10/968df4fba133dd18b8c65504c3cc5a3a6071e49f0706c6524711cdfab321a51debfeb506b9ff0a8f7dd8ce3015921d82fa51429d8f11d392cc68de1938703c33 + checksum: 10/063c4fd82e5022db7f53e85a3b31caa1c302e7d3f874b3acc751ee5fcf8f102068693e393dc5146cdeeb5850f2321366de4ebc5ef12ab81dae52e2c7113a6b49 languageName: node linkType: hard @@ -16500,22 +16497,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" @@ -17958,41 +17939,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 @@ -18266,14 +18247,14 @@ __metadata: linkType: hard "@slack/web-api@npm:^7.5.0": - version: 7.8.0 - resolution: "@slack/web-api@npm:7.8.0" + version: 7.9.3 + resolution: "@slack/web-api@npm:7.9.3" dependencies: "@slack/logger": "npm:^4.0.0" "@slack/types": "npm:^2.9.0" "@types/node": "npm:>=18.0.0" "@types/retry": "npm:0.12.0" - axios: "npm:^1.7.8" + axios: "npm:^1.8.3" eventemitter3: "npm:^5.0.1" form-data: "npm:^4.0.0" is-electron: "npm:2.2.2" @@ -18281,7 +18262,7 @@ __metadata: p-queue: "npm:^6" p-retry: "npm:^4" retry: "npm:^0.13.1" - checksum: 10/f2a698f853d0aaab11a23e9ce659e2cf3e43792eeb6861ef05258bbd2bb5cfe3bad8fc7bff4ee6fe471e67ec9fb6b22ef16be4478ab68f139df730337ebe15bb + checksum: 10/dc8aa95c8127a1155f0c0756bc819185da0b471feb5953dc118301e577e67f45ad4ef64d9459ff430b44f769344a6347d1636ad59267483e9ac0104611263a05 languageName: node linkType: hard @@ -19088,8 +19069,8 @@ __metadata: linkType: hard "@stoplight/spectral-core@npm:^1.18.0, @stoplight/spectral-core@npm:^1.18.3, @stoplight/spectral-core@npm:^1.19.2, @stoplight/spectral-core@npm:^1.19.4, @stoplight/spectral-core@npm:^1.8.1": - version: 1.19.5 - resolution: "@stoplight/spectral-core@npm:1.19.5" + version: 1.20.0 + resolution: "@stoplight/spectral-core@npm:1.20.0" dependencies: "@stoplight/better-ajv-errors": "npm:1.0.3" "@stoplight/json": "npm:~3.21.0" @@ -19112,7 +19093,7 @@ __metadata: pony-cause: "npm:^1.1.1" simple-eval: "npm:1.0.1" tslib: "npm:^2.8.1" - checksum: 10/db0f6c1c0ca67bc4a49c480259d261283ccb72958cd3a2a761dccbbbb1fdd04911df9c0a05f7ce4453e303de737206fbf3e799a1ace5db49d433a2848abe13b2 + checksum: 10/63628dcf4b1556db166a020dd78d17033908fa7d1c67c62739e35848e5d0e095714524b4c142aa7d6524fe556152f4dbb8cb388b36bc6e37026bf07c31a0e69b languageName: node linkType: hard @@ -19129,8 +19110,8 @@ __metadata: linkType: hard "@stoplight/spectral-formatters@npm:^1.1.0": - version: 1.4.3 - resolution: "@stoplight/spectral-formatters@npm:1.4.3" + version: 1.5.0 + resolution: "@stoplight/spectral-formatters@npm:1.5.0" dependencies: "@stoplight/path": "npm:^1.3.2" "@stoplight/spectral-core": "npm:^1.19.4" @@ -19145,13 +19126,13 @@ __metadata: strip-ansi: "npm:6.0" text-table: "npm:^0.2.0" tslib: "npm:^2.8.1" - checksum: 10/38cdb6dd756a5b859f0768bd7a6730d9ff816a8e21880385e75d0b663a98a2ca62283b6ab50bcce92384e0117d354813591faec9d5da85a3d6ed491afd5b1830 + checksum: 10/565f939d4363d6de357cb6292fce3f656ea106097b675562a958a2fb0b351f2ebc8516602ebdad83f57a73d6da178ce3e18e8a484b565d5c46e24aa588e7f04b languageName: node linkType: hard "@stoplight/spectral-functions@npm:^1.6.1, @stoplight/spectral-functions@npm:^1.7.2, @stoplight/spectral-functions@npm:^1.9.1": - version: 1.9.4 - resolution: "@stoplight/spectral-functions@npm:1.9.4" + version: 1.10.1 + resolution: "@stoplight/spectral-functions@npm:1.10.1" dependencies: "@stoplight/better-ajv-errors": "npm:1.0.3" "@stoplight/json": "npm:^3.17.1" @@ -19164,7 +19145,7 @@ __metadata: ajv-formats: "npm:~2.1.1" lodash: "npm:~4.17.21" tslib: "npm:^2.8.1" - checksum: 10/8da84358ccfcf60afc2f61db3296eef5718e9f837cfaec99a006faf42f5e1f7a6f47fbbe02161e39ffe6a5fe9dc5cacf1270ff59b22a8ba6264d6381d6a94d65 + checksum: 10/dceb3aa64ef5342183a1175ccf6d1a81e6c44dd0dd128a2b0b00f7d8b0eb467a47faac96b2a3a42554e99116af0e5a1d8be3d51ae82c3a96fc683d53fb0127ca languageName: node linkType: hard @@ -19194,8 +19175,8 @@ __metadata: linkType: hard "@stoplight/spectral-rulesets@npm:^1.14.1, @stoplight/spectral-rulesets@npm:^1.18.0": - version: 1.21.4 - resolution: "@stoplight/spectral-rulesets@npm:1.21.4" + version: 1.22.0 + resolution: "@stoplight/spectral-rulesets@npm:1.22.0" dependencies: "@asyncapi/specs": "npm:^6.8.0" "@stoplight/better-ajv-errors": "npm:1.0.3" @@ -19212,7 +19193,7 @@ __metadata: leven: "npm:3.1.0" lodash: "npm:~4.17.21" tslib: "npm:^2.8.1" - checksum: 10/f5154e70285e3e7caac24a33fec0904d342923402f4bc2fb0a4d184d1e9f8a70d555d7ed9118dda004b8fd5ad51357e57abc68b657315934a03beb0e55d842d5 + checksum: 10/1e93a302436b62532324dadb5c0cd1f89606533a8fefb1437288b6dec6c28c350d41723718b978c0c4c806cffe9019a2b8b0df5f71f78349a23f98a2f847c036 languageName: node linkType: hard @@ -19419,17 +19400,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" @@ -20772,8 +20742,8 @@ __metadata: linkType: hard "@testing-library/react@npm:^16.0.0": - version: 16.1.0 - resolution: "@testing-library/react@npm:16.1.0" + version: 16.3.0 + resolution: "@testing-library/react@npm:16.3.0" dependencies: "@babel/runtime": "npm:^7.12.5" peerDependencies: @@ -20787,7 +20757,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 10/2a20e0dbfadbc93d45a84e82281ed47deed54a6a5fc1461a523172d7fbc0481e8502cf98a2080f38aba94290b3d745671a1c9e320e6f76ad6afcca67c580b963 + checksum: 10/0ee9e31dd0d2396a924682d0e61a4ecc6bfab8eaff23dbf8a72c3c2ce22c116fa578148baeb4de75b968ef99d22e6e6aa0a00dba40286f71184918bb6bb5b06a languageName: node linkType: hard @@ -20809,7 +20779,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: @@ -20883,6 +20853,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" @@ -20971,10 +20976,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 @@ -21063,12 +21068,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 @@ -21171,12 +21176,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 @@ -21408,19 +21413,7 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:*": - version: 5.0.0 - resolution: "@types/express-serve-static-core@npm:5.0.0" - dependencies: - "@types/node": "npm:*" - "@types/qs": "npm:*" - "@types/range-parser": "npm:*" - "@types/send": "npm:*" - checksum: 10/fc40cdeae61113d8b2335f4b0f9334a7a64388a0931f2e98f8fc9bdadd0b13b501a70da14c256ae4aa140db49bd2eff75a99a683266d561e62540784a61dc489 - languageName: node - linkType: hard - -"@types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5": +"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5": version: 4.19.6 resolution: "@types/express-serve-static-core@npm:4.19.6" dependencies: @@ -21442,14 +21435,14 @@ __metadata: linkType: hard "@types/express@npm:*, @types/express@npm:^4.16.1, @types/express@npm:^4.17.21, @types/express@npm:^4.17.6": - version: 4.17.21 - resolution: "@types/express@npm:4.17.21" + version: 4.17.23 + resolution: "@types/express@npm:4.17.23" dependencies: "@types/body-parser": "npm:*" "@types/express-serve-static-core": "npm:^4.17.33" "@types/qs": "npm:*" "@types/serve-static": "npm:*" - checksum: 10/7a6d26cf6f43d3151caf4fec66ea11c9d23166e4f3102edfe45a94170654a54ea08cf3103d26b3928d7ebcc24162c90488e33986b7e3a5f8941225edd5eb18c7 + checksum: 10/cf4d540bbd90801cdc79a46107b8873404698a7fd0c3e8dd42989d52d3bd7f5b8768672e54c20835e41e27349c319bb47a404ad14c0f8db0e9d055ba1cb8a05b languageName: node linkType: hard @@ -21783,9 +21776,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.151": - version: 4.17.17 - resolution: "@types/lodash@npm:4.17.17" - checksum: 10/496459a3cb1a0733bb60532de3899ad6297717af0b9b26ad6821154b2005fec86f29ccd47a2e6f4da4a8c7c818bb8ae73901144e8057ea86b7b02a3d7bb9d13f + version: 4.17.20 + resolution: "@types/lodash@npm:4.17.20" + checksum: 10/8cd8ad3bd78d2e06a93ae8d6c9907981d5673655fec7cb274a4d9a59549aab5bb5b3017361280773b8990ddfccf363e14d1b37c97af8a9fe363de677f9a61524 languageName: node linkType: hard @@ -21909,12 +21902,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 @@ -22034,6 +22027,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" @@ -22118,25 +22120,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 @@ -22185,9 +22176,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 @@ -22273,15 +22264,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" @@ -22849,6 +22831,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" @@ -22879,6 +22874,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" @@ -22915,6 +22919,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" @@ -22970,6 +22981,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" @@ -23047,6 +23078,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" @@ -23415,6 +23456,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" @@ -24870,6 +24968,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" @@ -25234,6 +25339,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" @@ -25499,7 +25611,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.0.0, axios@npm:^1.6.0, axios@npm:^1.7.4, axios@npm:^1.7.7, axios@npm:^1.7.8": +"axios@npm:^1.0.0, axios@npm:^1.6.0, axios@npm:^1.7.4, axios@npm:^1.7.7, axios@npm:^1.8.3": version: 1.10.0 resolution: "axios@npm:1.10.0" dependencies: @@ -25857,14 +25969,14 @@ __metadata: languageName: node linkType: hard -"better-sqlite3@npm:^11.0.0": - version: 11.7.2 - resolution: "better-sqlite3@npm:11.7.2" +"better-sqlite3@npm:^12.0.0": + version: 12.2.0 + resolution: "better-sqlite3@npm:12.2.0" dependencies: bindings: "npm:^1.5.0" node-gyp: "npm:latest" prebuild-install: "npm:^7.1.1" - checksum: 10/49e1d8847560058d00c87177dfa6ef6bf713cb0122795c8f43143ac3154608f2ff83d4180ab00c7c24f5c23f0bcfe96bb47ac08b3ef5081ed41f46869df594f6 + checksum: 10/2662e321237624d5813a7b97528dfc11fc5110b068d57f4096de82d7136e7e4a4b722a2a4266ddfb5095070712fd3d2542f6212ccb68e2d3eb2042498269e1cf languageName: node linkType: hard @@ -27298,7 +27410,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 @@ -27632,6 +27744,24 @@ __metadata: languageName: node linkType: hard +"concurrently@npm:^9.2.0": + version: 9.2.0 + resolution: "concurrently@npm:9.2.0" + dependencies: + chalk: "npm:^4.1.2" + lodash: "npm:^4.17.21" + rxjs: "npm:^7.8.1" + shell-quote: "npm:^1.8.1" + supports-color: "npm:^8.1.1" + tree-kill: "npm:^1.2.2" + yargs: "npm:^17.7.2" + bin: + conc: dist/bin/concurrently.js + concurrently: dist/bin/concurrently.js + checksum: 10/fdf5d3b583640b11ef84fab3ffdf77ed9c6878fa0a56f6787b6cd46b7011305c71d9e0067a814ca4fa52bea6f20ddb466bb97a13d61999628e43e550ddad7c93 + languageName: node + linkType: hard + "conf@npm:^10.2.0": version: 10.2.0 resolution: "conf@npm:10.2.0" @@ -28592,16 +28722,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" @@ -28618,6 +28738,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" @@ -29031,6 +29158,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" @@ -29133,6 +29274,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" @@ -30618,10 +30861,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 @@ -30894,7 +31137,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:^" @@ -30934,6 +31176,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" @@ -30968,7 +31211,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:^" @@ -31004,6 +31246,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" @@ -31069,7 +31312,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" @@ -31223,11 +31466,11 @@ __metadata: linkType: hard "express-rate-limit@npm:^7.5.0": - version: 7.5.0 - resolution: "express-rate-limit@npm:7.5.0" + version: 7.5.1 + resolution: "express-rate-limit@npm:7.5.1" peerDependencies: - express: ^4.11 || 5 || ^5.0.0-beta.1 - checksum: 10/eff34c83bf586789933a332a339b66649e2cca95c8e977d193aa8bead577d3182ac9f0e9c26f39389287539b8038890ff023f910b54ebb506a26a2ce135b92ca + express: ">= 4.11" + checksum: 10/357c3398450144ab7bbce2841d0bf4f93a0f3fd9d1d5ed9a0ee331b557af969cc790941dc37b47f8d9b5672964aa0e31666f770e1f48b334dc7d1e69f6433040 languageName: node linkType: hard @@ -31609,6 +31852,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" @@ -31634,15 +31887,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 @@ -31687,6 +31940,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" @@ -31804,15 +32078,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 @@ -32105,6 +32379,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" @@ -32393,7 +32676,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: @@ -32406,6 +32689,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" @@ -32416,6 +32710,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" @@ -32448,6 +32753,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" @@ -32487,6 +32802,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" @@ -32684,15 +33006,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 @@ -32712,23 +33038,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: @@ -32897,6 +33207,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" @@ -32906,7 +33227,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: @@ -32940,6 +33276,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" @@ -32947,17 +33290,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 @@ -33043,15 +33385,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" @@ -33177,6 +33510,13 @@ __metadata: languageName: node linkType: hard +"gsap@npm:^3.13.0": + version: 3.13.0 + resolution: "gsap@npm:3.13.0" + checksum: 10/1908d51cbdf8f0bec8a69919af352d743a06529639a89f750f1c02e9a165d3ea816f867569df222ee7bfc14e23e268ebeb51dc5df0687fa7918ddd5d3b3efaec + languageName: node + linkType: hard + "gtoken@npm:^7.0.0": version: 7.0.1 resolution: "gtoken@npm:7.0.1" @@ -33187,6 +33527,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" @@ -34284,9 +34634,9 @@ __metadata: languageName: node linkType: hard -"iovalkey@npm:^0.3.1": - version: 0.3.1 - resolution: "iovalkey@npm:0.3.1" +"iovalkey@npm:^0.3.3": + version: 0.3.3 + resolution: "iovalkey@npm:0.3.3" dependencies: "@iovalkey/commands": "npm:^0.1.0" cluster-key-slot: "npm:^1.1.0" @@ -34297,7 +34647,7 @@ __metadata: redis-errors: "npm:^1.2.0" redis-parser: "npm:^3.0.0" standard-as-callback: "npm:^2.1.0" - checksum: 10/afe5e0218810d902263dca2b22dd4501fb74698111f1850804d0948bd6a97793a7f5006757f9b6e8c8131bac6bd532d07ad971e7776bed7f6dc1f6e471706c53 + checksum: 10/39368842e6a9dbc85e92dfcd4c1c917a76240bac5c4210e19a0bd3bc7984af9b567dce5de7c560c4517d5d4cb03af229f38582c1dd055c6fd452060774318e8c languageName: node linkType: hard @@ -34749,6 +35099,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" @@ -34870,6 +35227,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" @@ -35006,6 +35370,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" @@ -37910,6 +38281,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" @@ -37919,12 +38317,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 @@ -39083,15 +39481,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" @@ -39250,7 +39639,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 @@ -39446,6 +39835,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" @@ -39453,6 +39854,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" @@ -39543,8 +39958,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" @@ -39571,7 +39986,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10/bc90bc34a0b9e978e662f33fa630a0de66c4b6eff3a92b41efa08bf67d79b43e4a961a17b0d274580393c912f4ac6226c76a8bc33148799b1ee43477df712c26 + checksum: 10/e2f25dda1aba66c7444c29c41d3157cb15c0332055ab7ebfb74ef4b506e7b90098cf37c577768edb5b2b2dbf0d6ed6a7a3ca8ee6da3d72df5a25823d82f33316 languageName: node linkType: hard @@ -39694,12 +40109,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 @@ -39942,6 +40357,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" @@ -40107,6 +40533,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" @@ -40619,7 +41054,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 @@ -41329,6 +41764,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" @@ -41600,7 +42042,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: @@ -41703,13 +42145,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" @@ -41759,13 +42194,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" @@ -41795,21 +42223,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" @@ -42033,27 +42446,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.53.0": - version: 1.53.0 - resolution: "playwright-core@npm:1.53.0" +"playwright-core@npm:1.53.2": + version: 1.53.2 + resolution: "playwright-core@npm:1.53.2" bin: playwright-core: cli.js - checksum: 10/881f27a9b7edd9954700489a5a4212cb91bcada226fd1d79a239b2eab0f333df1e2e41e275e6fa846d7f57c6a92afe14dca33ca7a2ce303dfb687d02511b7c69 + checksum: 10/575c37b66aa62e1300d8b42d4b021c9304a35266ea47b6f0c36b429c40674082700b7172ee3641de7451cd2a4c736c42e0e39fd5f6a7ba4c81a6eefd8c104efd languageName: node linkType: hard -"playwright@npm:1.53.0": - version: 1.53.0 - resolution: "playwright@npm:1.53.0" +"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.0" + playwright-core: "npm:1.53.2" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/0b0258630f39b4d6ff1555d008ee4d591fe45cbe1e0f643a612397e3e6b1f7a99a2037a957eaa7351edd907ba10966ba105b2d244eafd1b247378910b660f086 + checksum: 10/1c860c52a77f32793d7b1b5f5b15da9b809b8a09a82e5c89f79442fe9708ff6314b6ee6d13aa0961a6c9fddc9209f0a109ac524bdf586e0df52b641e96fa759d languageName: node linkType: hard @@ -42535,14 +42948,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 @@ -42553,13 +42979,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" @@ -42567,15 +42986,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" @@ -42583,13 +42993,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" @@ -42599,20 +43002,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" @@ -42663,6 +43052,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" @@ -42751,6 +43165,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" @@ -42920,7 +43343,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: @@ -43198,6 +43621,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" @@ -43745,16 +44175,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" @@ -44166,18 +44586,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" @@ -44805,6 +45213,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" @@ -44842,6 +45270,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" @@ -44893,7 +45328,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: @@ -44932,7 +45367,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: @@ -45346,6 +45781,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" @@ -45413,7 +45849,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:7.8.2, rxjs@npm:^7.2.0, rxjs@npm:^7.5.5": +"rxjs@npm:7.8.2, rxjs@npm:^7.2.0, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.2 resolution: "rxjs@npm:7.8.2" dependencies: @@ -45531,6 +45967,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" @@ -45870,9 +46318,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 @@ -46873,7 +47321,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: @@ -47110,6 +47558,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" @@ -47246,13 +47705,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 @@ -47363,6 +47821,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" @@ -48303,12 +48772,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 @@ -48326,6 +48795,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" @@ -48720,19 +49201,19 @@ __metadata: linkType: hard "typedoc@npm:^0.28.0": - version: 0.28.4 - resolution: "typedoc@npm:0.28.4" + version: 0.28.8 + resolution: "typedoc@npm:0.28.8" 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/14e131d8602265936303d72b5652e05a804ed6e5c839c12af99a8e89f6741afc891c9f208255b96ef703646a92faf24206e6cdee486c431327a4cf6456e71f4f languageName: node linkType: hard @@ -48773,6 +49254,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" @@ -48803,6 +49294,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" @@ -49803,6 +50304,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" @@ -50540,12 +51048,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