diff --git a/.changeset/add-missing-transitive-deps.md b/.changeset/add-missing-transitive-deps.md deleted file mode 100644 index 83f87fcc7e..0000000000 --- a/.changeset/add-missing-transitive-deps.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/ui': patch -'@backstage/plugin-notifications': patch -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Added missing dependencies that were previously only available transitively. diff --git a/.changeset/add-service-unavailable-error-name.md b/.changeset/add-service-unavailable-error-name.md deleted file mode 100644 index 78647f7a56..0000000000 --- a/.changeset/add-service-unavailable-error-name.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/errors': patch ---- - -Added explicit `name` property to `ServiceUnavailableError` for consistency with all other error classes, making it resilient to minification. diff --git a/.changeset/brave-groups-learn.md b/.changeset/brave-groups-learn.md deleted file mode 100644 index 773e8eed49..0000000000 --- a/.changeset/brave-groups-learn.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Added `isPending` prop to Alert, Button, ButtonIcon, Table, and TableRoot as a replacement for the `loading` prop, aligning with React Aria naming conventions. The `loading` prop is now deprecated but still supported as an alias. CSS selectors now use `data-ispending` instead of `data-loading` for styling pending states; `data-loading` is still emitted for backward compatibility but will be removed alongside the `loading` prop. - -**Affected components:** Alert, Button, ButtonIcon, Table, TableRoot diff --git a/.changeset/chubby-candies-cry.md b/.changeset/chubby-candies-cry.md deleted file mode 100644 index 75394f823e..0000000000 --- a/.changeset/chubby-candies-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app': patch ---- - -Migrated React Aria imports from individual packages (`@react-aria/toast`, `@react-aria/button`, `@react-stately/toast`) to the monopackages (`react-aria`, `react-stately`). diff --git a/.changeset/clamp-react-aria-deps.md b/.changeset/clamp-react-aria-deps.md deleted file mode 100644 index 521670e40d..0000000000 --- a/.changeset/clamp-react-aria-deps.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/ui': patch -'@backstage/plugin-app': patch -'@backstage/plugin-app-visualizer': patch -'@backstage/plugin-notifications': patch ---- - -Tightened React Aria dependency version ranges from `^` to `~` to prevent unintended minor version upgrades. diff --git a/.changeset/deduplicate-joinpaths-routing.md b/.changeset/deduplicate-joinpaths-routing.md deleted file mode 100644 index 8a17fbc17b..0000000000 --- a/.changeset/deduplicate-joinpaths-routing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Internal cleanup of routing utilities. diff --git a/.changeset/delegate-attach-mock-api-factory.md b/.changeset/delegate-attach-mock-api-factory.md deleted file mode 100644 index 0d1f47bd64..0000000000 --- a/.changeset/delegate-attach-mock-api-factory.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-test-utils': patch ---- - -Removed internal `mockWithApiFactory` helper in favor of using `attachMockApiFactory` directly. diff --git a/.changeset/extension-point-middleware-backend-app-api.md b/.changeset/extension-point-middleware-backend-app-api.md deleted file mode 100644 index 2d0ea0dfbc..0000000000 --- a/.changeset/extension-point-middleware-backend-app-api.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': minor ---- - -Added `ExtensionPointFactoryMiddleware` type and `createExtensionPointFactoryMiddleware` helper to reimplement extension point outputs at backend creation time. diff --git a/.changeset/extension-point-middleware-backend-defaults.md b/.changeset/extension-point-middleware-backend-defaults.md deleted file mode 100644 index 73add7bc7f..0000000000 --- a/.changeset/extension-point-middleware-backend-defaults.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Exported `defaultServiceFactories` to allow use with `createSpecializedBackend` for advanced configuration like `extensionPointFactoryMiddleware`. diff --git a/.changeset/fix-alter-target-nullability.md b/.changeset/fix-alter-target-nullability.md deleted file mode 100644 index 9116b9d968..0000000000 --- a/.changeset/fix-alter-target-nullability.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixed several database migration `down` functions that were not properly reversible, causing the SQL report to show warnings: - -- `20241003170511_alter_target_in_locations.js`: both `up` and `down` now include `.notNullable()` when altering the `locations.target` column, preventing the `NOT NULL` constraint from being accidentally dropped when widening the column type from `varchar(255)` to `text`. -- `20220116144621_remove_legacy.js`: the `down` function now properly recreates the three dropped legacy tables (`entities`, `entities_search`, `entities_relations`) with correct columns and indices. -- `20210302150147_refresh_state.js`: the `down` function now drops dependent tables in the correct order (avoiding a FK constraint violation) and fixes a typo where the table was referred to as `references` instead of `refresh_state_references`. -- `20201005122705_add_entity_full_name.js`: the `down` function now drops the `full_name` column from `entities` (not `entities_search`), and restores the `entities_unique_name` index with the correct column order `(kind, name, namespace)`. -- `20200702153613_entities.js`: the `down` function now uses `table.integer('generation')` instead of `table.string('generation')`, restoring the correct column type. diff --git a/.changeset/fix-dialog-dark-theme-selector.md b/.changeset/fix-dialog-dark-theme-selector.md deleted file mode 100644 index 287278d3a5..0000000000 --- a/.changeset/fix-dialog-dark-theme-selector.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed dark mode background for Dialog component by correcting the theme attribute selector from `data-theme` to `data-theme-mode`. - -**Affected components:** Dialog diff --git a/.changeset/fix-embedded-postgres-config-paths.md b/.changeset/fix-embedded-postgres-config-paths.md deleted file mode 100644 index 7697636fb5..0000000000 --- a/.changeset/fix-embedded-postgres-config-paths.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli-module-build': patch ---- - -Fixed config path resolution for the embedded-postgres database client detection to resolve paths relative to the target package directory rather than the workspace root. diff --git a/.changeset/fix-facets-perf-regression.md b/.changeset/fix-facets-perf-regression.md deleted file mode 100644 index 71f293271a..0000000000 --- a/.changeset/fix-facets-perf-regression.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixed a performance regression in the `/entity-facets` endpoint when filters or permission conditions are applied, by routing the EXISTS-based filter through `final_entities` instead of correlating against the much larger `search` table. diff --git a/.changeset/fix-implicit-any-renderInTestApp.md b/.changeset/fix-implicit-any-renderInTestApp.md deleted file mode 100644 index 1db848a202..0000000000 --- a/.changeset/fix-implicit-any-renderInTestApp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-test-utils': patch ---- - -Added explicit type annotations to `.map()` callback parameters in `renderInTestApp` to avoid implicit `any` errors with newer TypeScript versions. diff --git a/.changeset/fix-scheduler-sleep-overflow.md b/.changeset/fix-scheduler-sleep-overflow.md deleted file mode 100644 index bf51ade22d..0000000000 --- a/.changeset/fix-scheduler-sleep-overflow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Fixed scheduler `sleep` firing immediately for durations longer than ~24.8 days, caused by Node.js `setTimeout` overflowing its 32-bit millisecond limit. diff --git a/.changeset/fix-tabs-active-indicator-disappearing.md b/.changeset/fix-tabs-active-indicator-disappearing.md deleted file mode 100644 index c8537940c9..0000000000 --- a/.changeset/fix-tabs-active-indicator-disappearing.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed an issue where the active tab indicator would disappear shortly after page load for uncontrolled Tabs. - -**Affected components:** Tabs diff --git a/.changeset/fix-widget-resize-after-edit.md b/.changeset/fix-widget-resize-after-edit.md deleted file mode 100644 index d1f2a1b017..0000000000 --- a/.changeset/fix-widget-resize-after-edit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Fixed widgets not being movable or resizable after saved edits. Previously, entering edit mode didn't restore `isDraggable` and `isResizable`. diff --git a/.changeset/free-ways-flow.md b/.changeset/free-ways-flow.md deleted file mode 100644 index 4359076b60..0000000000 --- a/.changeset/free-ways-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Made the TechDocs sidebar positioning at tablet breakpoints configurable via CSS custom properties, allowing apps with custom sidebar widths to override the defaults. The available properties are `--techdocs-sidebar-closed-offset-pinned`, `--techdocs-sidebar-closed-offset-collapsed`, and `--techdocs-sidebar-open-translate`. diff --git a/.changeset/funny-areas-rescue.md b/.changeset/funny-areas-rescue.md deleted file mode 100644 index 0b13201f82..0000000000 --- a/.changeset/funny-areas-rescue.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': minor ---- - -Add support for flex item props (`grow`, `shrink`, and `basis`) to `Box`, `Card`, `Grid`, and `Flex` itself. - -**Affected components:** Box, Card, Grid, Flex diff --git a/.changeset/gold-drinks-poke.md b/.changeset/gold-drinks-poke.md deleted file mode 100644 index 46b0440bed..0000000000 --- a/.changeset/gold-drinks-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Updated React Aria dependencies to v1.17.0 and migrated imports from individual `@react-aria/*` and `@react-stately/*` packages to the monopackages (`react-aria`, `react-stately`). This fixes a type resolution error for `@react-types/table` that occurred in new app installations. diff --git a/.changeset/move-registermswtesthooks-to-test-utils.md b/.changeset/move-registermswtesthooks-to-test-utils.md deleted file mode 100644 index aa4de48ab4..0000000000 --- a/.changeset/move-registermswtesthooks-to-test-utils.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Moved `registerMswTestHooks` to test files. diff --git a/.changeset/owner-column-cleanup.md b/.changeset/owner-column-cleanup.md deleted file mode 100644 index 709f74f781..0000000000 --- a/.changeset/owner-column-cleanup.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Simplified the `OwnerEntityColumn` in the task list to rely on `EntityRefLink` and the entity presentation API instead of manually fetching entities from the catalog. diff --git a/.changeset/pre.json b/.changeset/pre.json index 107359dbb6..52872da56f 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,262 +2,230 @@ "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.0.34", - "@backstage/app-defaults": "1.7.7", - "app-example-plugin": "0.0.34", - "example-app-legacy": "0.2.120", - "example-backend": "0.0.49", - "@backstage/backend-app-api": "1.6.1", - "@backstage/backend-defaults": "0.17.0", + "example-app": "0.0.35", + "@backstage/app-defaults": "1.7.8", + "app-example-plugin": "0.0.35", + "example-app-legacy": "0.2.121", + "example-backend": "0.0.50", + "@backstage/backend-app-api": "1.7.0", + "@backstage/backend-defaults": "0.17.1", "@backstage/backend-dev-utils": "0.1.7", - "@backstage/backend-dynamic-feature-service": "0.8.1", + "@backstage/backend-dynamic-feature-service": "0.8.2", "@internal/backend": "0.0.1", - "@backstage/backend-openapi-utils": "0.6.8", - "@backstage/backend-plugin-api": "1.9.0", - "@backstage/backend-test-utils": "1.11.2", - "@backstage/catalog-client": "1.15.0", - "@backstage/catalog-model": "1.8.0", - "@backstage/cli": "0.36.1", - "@backstage/cli-common": "0.2.1", - "@backstage/cli-defaults": "0.1.1", - "@internal/cli": "0.0.3", - "@backstage/cli-module-actions": "0.1.0", - "@backstage/cli-module-auth": "0.1.1", - "@backstage/cli-module-build": "0.1.1", - "@backstage/cli-module-config": "0.1.1", - "@backstage/cli-module-github": "0.1.1", - "@backstage/cli-module-info": "0.1.1", - "@backstage/cli-module-lint": "0.1.1", - "@backstage/cli-module-maintenance": "0.1.1", - "@backstage/cli-module-migrate": "0.1.1", - "@backstage/cli-module-new": "0.1.2", - "@backstage/cli-module-test-jest": "0.1.1", - "@backstage/cli-module-translations": "0.1.1", - "@backstage/cli-node": "0.3.1", - "@backstage/codemods": "0.1.56", - "@backstage/config": "1.3.7", - "@backstage/config-loader": "1.10.10", - "@backstage/core-app-api": "1.20.0", - "@backstage/core-compat-api": "0.5.10", - "@backstage/core-components": "0.18.9", - "@backstage/core-plugin-api": "1.12.5", - "@backstage/create-app": "0.8.2", - "@backstage/dev-utils": "1.1.22", - "e2e-test": "0.2.39", + "@backstage/backend-openapi-utils": "0.6.9", + "@backstage/backend-plugin-api": "1.9.1", + "@backstage/backend-test-utils": "1.11.3", + "@backstage/catalog-client": "1.15.1", + "@backstage/catalog-model": "1.9.0", + "@backstage/cli": "0.36.2", + "@backstage/cli-common": "0.2.2", + "@backstage/cli-defaults": "0.1.2", + "@internal/cli": "0.0.4", + "@backstage/cli-module-actions": "0.1.1", + "@backstage/cli-module-auth": "0.1.2", + "@backstage/cli-module-build": "0.1.3", + "@backstage/cli-module-config": "0.1.2", + "@backstage/cli-module-github": "0.1.2", + "@backstage/cli-module-info": "0.1.2", + "@backstage/cli-module-lint": "0.1.2", + "@backstage/cli-module-maintenance": "0.1.2", + "@backstage/cli-module-migrate": "0.1.2", + "@backstage/cli-module-new": "0.1.3", + "@backstage/cli-module-test-jest": "0.1.2", + "@backstage/cli-module-translations": "0.1.2", + "@backstage/cli-node": "0.3.2", + "@backstage/codemods": "0.1.57", + "@backstage/config": "1.3.8", + "@backstage/config-loader": "1.10.11", + "@backstage/core-app-api": "1.20.1", + "@backstage/core-compat-api": "0.5.11", + "@backstage/core-components": "0.18.10", + "@backstage/core-plugin-api": "1.12.6", + "@backstage/create-app": "0.8.3", + "@backstage/dev-utils": "1.1.23", + "e2e-test": "0.2.40", "@backstage/e2e-test-utils": "0.1.2", - "@backstage/errors": "1.3.0", - "@backstage/eslint-plugin": "0.2.3", - "@backstage/filter-predicates": "0.1.2", - "@backstage/frontend-app-api": "0.16.2", - "@backstage/frontend-defaults": "0.5.1", - "@backstage/frontend-dev-utils": "0.1.1", - "@backstage/frontend-dynamic-feature-loader": "0.1.11", - "@internal/frontend": "0.0.19", - "@backstage/frontend-plugin-api": "0.16.0", - "@backstage/frontend-test-utils": "0.5.2", - "@backstage/integration": "2.0.1", - "@backstage/integration-aws-node": "0.1.21", - "@backstage/integration-react": "1.2.17", - "@backstage/module-federation-common": "0.1.3", + "@backstage/errors": "1.3.1", + "@backstage/eslint-plugin": "0.3.0", + "@backstage/filter-predicates": "0.1.3", + "@backstage/frontend-app-api": "0.16.3", + "@backstage/frontend-defaults": "0.5.2", + "@backstage/frontend-dev-utils": "0.1.2", + "@backstage/frontend-dynamic-feature-loader": "0.1.12", + "@internal/frontend": "0.0.20", + "@backstage/frontend-plugin-api": "0.17.0", + "@backstage/frontend-test-utils": "0.6.0", + "@backstage/integration": "2.0.2", + "@backstage/integration-aws-node": "0.2.0", + "@backstage/integration-react": "1.2.18", + "@backstage/module-federation-common": "0.1.4", "@internal/opaque": "0.0.1", "@backstage/release-manifests": "0.0.13", - "@backstage/repo-tools": "0.17.1", - "@internal/scaffolder": "0.0.20", - "@techdocs/cli": "1.10.7", - "techdocs-cli-embedded-app": "0.2.119", - "@backstage/test-utils": "1.7.17", + "@backstage/repo-tools": "0.17.2", + "@internal/scaffolder": "0.0.21", + "@techdocs/cli": "1.11.0", + "techdocs-cli-embedded-app": "0.2.120", + "@backstage/test-utils": "1.7.18", "@backstage/theme": "0.7.3", "@backstage/types": "1.2.2", - "@backstage/ui": "0.14.0", + "@backstage/ui": "0.15.0", "@backstage/version-bridge": "1.0.12", - "yarn-plugin-backstage": "0.0.11", - "@backstage/plugin-api-docs": "0.14.0", + "yarn-plugin-backstage": "0.0.12", + "@backstage/plugin-api-docs": "0.14.1", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.11", - "@backstage/plugin-app": "0.4.3", - "@backstage/plugin-app-backend": "0.5.13", - "@backstage/plugin-app-node": "0.1.44", - "@backstage/plugin-app-react": "0.2.2", - "@backstage/plugin-app-visualizer": "0.2.2", - "@backstage/plugin-auth": "0.1.7", - "@backstage/plugin-auth-backend": "0.28.0", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.14", - "@backstage/plugin-auth-backend-module-auth0-provider": "0.4.0", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.15", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.19", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.14", - "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.14", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.14", - "@backstage/plugin-auth-backend-module-github-provider": "0.5.2", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.4.2", - "@backstage/plugin-auth-backend-module-google-provider": "0.3.14", - "@backstage/plugin-auth-backend-module-guest-provider": "0.2.18", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.14", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.14", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.19", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.15", - "@backstage/plugin-auth-backend-module-okta-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.14", - "@backstage/plugin-auth-backend-module-openshift-provider": "0.1.6", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.13", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.13", - "@backstage/plugin-auth-node": "0.7.0", - "@backstage/plugin-auth-react": "0.1.26", - "@backstage/plugin-bitbucket-cloud-common": "0.3.9", - "@backstage/plugin-catalog": "2.0.2", - "@backstage/plugin-catalog-backend": "3.6.0", - "@backstage/plugin-catalog-backend-module-aws": "0.4.22", - "@backstage/plugin-catalog-backend-module-azure": "0.3.16", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.13", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.10", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.10", - "@backstage/plugin-catalog-backend-module-gcp": "0.3.18", - "@backstage/plugin-catalog-backend-module-gerrit": "0.3.13", - "@backstage/plugin-catalog-backend-module-gitea": "0.1.11", - "@backstage/plugin-catalog-backend-module-github": "0.13.1", - "@backstage/plugin-catalog-backend-module-github-org": "0.3.21", - "@backstage/plugin-catalog-backend-module-gitlab": "0.8.2", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.20", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.11", - "@backstage/plugin-catalog-backend-module-ldap": "0.12.4", - "@backstage/plugin-catalog-backend-module-logs": "0.1.21", - "@backstage/plugin-catalog-backend-module-msgraph": "0.9.2", - "@backstage/plugin-catalog-backend-module-openapi": "0.2.21", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.21", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.19", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.10", - "@backstage/plugin-catalog-common": "1.1.9", - "@backstage/plugin-catalog-graph": "0.6.1", - "@backstage/plugin-catalog-import": "0.13.12", - "@backstage/plugin-catalog-node": "2.2.0", - "@backstage/plugin-catalog-react": "2.1.2", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.29", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.14", - "@backstage/plugin-config-schema": "0.1.79", - "@backstage/plugin-devtools": "0.1.38", - "@backstage/plugin-devtools-backend": "0.5.16", - "@backstage/plugin-devtools-common": "0.1.24", - "@backstage/plugin-devtools-react": "0.2.1", - "@backstage/plugin-events-backend": "0.6.1", - "@backstage/plugin-events-backend-module-aws-sqs": "0.4.21", - "@backstage/plugin-events-backend-module-azure": "0.2.30", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.30", - "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.11", - "@backstage/plugin-events-backend-module-gerrit": "0.2.30", - "@backstage/plugin-events-backend-module-github": "0.4.11", - "@backstage/plugin-events-backend-module-gitlab": "0.3.11", - "@backstage/plugin-events-backend-module-google-pubsub": "0.2.2", - "@backstage/plugin-events-backend-module-kafka": "0.3.3", - "@backstage/plugin-events-backend-test-utils": "0.1.54", - "@backstage/plugin-events-node": "0.4.21", - "@internal/plugin-todo-list": "1.0.50", - "@internal/plugin-todo-list-backend": "1.0.49", - "@internal/plugin-todo-list-common": "1.0.30", - "@backstage/plugin-gateway-backend": "1.1.4", - "@backstage/plugin-home": "0.9.4", - "@backstage/plugin-home-react": "0.1.37", - "@backstage/plugin-kubernetes": "0.12.18", - "@backstage/plugin-kubernetes-backend": "0.21.3", - "@backstage/plugin-kubernetes-cluster": "0.0.36", - "@backstage/plugin-kubernetes-common": "0.9.11", - "@backstage/plugin-kubernetes-node": "0.4.3", - "@backstage/plugin-kubernetes-react": "0.5.18", - "@backstage/plugin-mcp-actions-backend": "0.1.12", - "@backstage/plugin-mui-to-bui": "0.2.6", - "@backstage/plugin-notifications": "0.5.16", - "@backstage/plugin-notifications-backend": "0.6.4", - "@backstage/plugin-notifications-backend-module-email": "0.3.20", - "@backstage/plugin-notifications-backend-module-slack": "0.4.1", - "@backstage/plugin-notifications-common": "0.2.2", - "@backstage/plugin-notifications-node": "0.2.25", - "@backstage/plugin-org": "0.7.1", - "@backstage/plugin-org-react": "0.1.49", - "@backstage/plugin-permission-backend": "0.7.11", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.18", - "@backstage/plugin-permission-common": "0.9.8", - "@backstage/plugin-permission-node": "0.10.12", - "@backstage/plugin-permission-react": "0.5.0", - "@backstage/plugin-proxy-backend": "0.6.12", - "@backstage/plugin-proxy-node": "0.1.14", - "@backstage/plugin-scaffolder": "1.36.2", - "@backstage/plugin-scaffolder-backend": "3.4.0", - "@backstage/plugin-scaffolder-backend-module-azure": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.3.5", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.20", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.22", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-github": "0.9.8", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.11.5", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.21", - "@backstage/plugin-scaffolder-backend-module-rails": "0.5.20", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.3.3", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.21", - "@backstage/plugin-scaffolder-common": "2.1.0", - "@backstage/plugin-scaffolder-node": "0.13.2", - "@backstage/plugin-scaffolder-node-test-utils": "0.3.10", - "@backstage/plugin-scaffolder-react": "1.20.1", - "@backstage/plugin-search": "1.7.1", - "@backstage/plugin-search-backend": "2.1.1", - "@backstage/plugin-search-backend-module-catalog": "0.3.14", - "@backstage/plugin-search-backend-module-elasticsearch": "1.8.2", - "@backstage/plugin-search-backend-module-explore": "0.3.13", - "@backstage/plugin-search-backend-module-pg": "0.5.54", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.19", - "@backstage/plugin-search-backend-module-techdocs": "0.4.13", - "@backstage/plugin-search-backend-node": "1.4.3", - "@backstage/plugin-search-common": "1.2.23", - "@backstage/plugin-search-react": "1.11.1", - "@backstage/plugin-signals": "0.0.30", - "@backstage/plugin-signals-backend": "0.3.14", - "@backstage/plugin-signals-node": "0.2.0", - "@backstage/plugin-signals-react": "0.0.21", - "@backstage/plugin-techdocs": "1.17.3", - "@backstage/plugin-techdocs-addons-test-utils": "2.0.4", - "@backstage/plugin-techdocs-backend": "2.1.7", + "@backstage/plugin-app": "0.4.6", + "@backstage/plugin-app-backend": "0.5.14", + "@backstage/plugin-app-node": "0.1.45", + "@backstage/plugin-app-react": "0.2.3", + "@backstage/plugin-app-visualizer": "0.2.4", + "@backstage/plugin-auth": "0.1.8", + "@backstage/plugin-auth-backend": "0.29.0", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.15", + "@backstage/plugin-auth-backend-module-auth0-provider": "0.4.1", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.16", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.20", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.15", + "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.15", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.15", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.15", + "@backstage/plugin-auth-backend-module-github-provider": "0.5.3", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.4.3", + "@backstage/plugin-auth-backend-module-google-provider": "0.3.15", + "@backstage/plugin-auth-backend-module-guest-provider": "0.2.19", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.15", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.15", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.20", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.16", + "@backstage/plugin-auth-backend-module-okta-provider": "0.2.15", + "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.15", + "@backstage/plugin-auth-backend-module-openshift-provider": "0.1.7", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.14", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.14", + "@backstage/plugin-auth-node": "0.7.1", + "@backstage/plugin-auth-react": "0.1.27", + "@backstage/plugin-bitbucket-cloud-common": "0.3.10", + "@backstage/plugin-catalog": "2.0.5", + "@backstage/plugin-catalog-backend": "3.7.0", + "@backstage/plugin-catalog-backend-module-ai-model": "0.1.0", + "@backstage/plugin-catalog-backend-module-aws": "0.4.23", + "@backstage/plugin-catalog-backend-module-azure": "0.3.17", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.14", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.11", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.11", + "@backstage/plugin-catalog-backend-module-gcp": "0.3.19", + "@backstage/plugin-catalog-backend-module-gerrit": "0.3.14", + "@backstage/plugin-catalog-backend-module-gitea": "0.1.12", + "@backstage/plugin-catalog-backend-module-github": "0.13.2", + "@backstage/plugin-catalog-backend-module-github-org": "0.3.22", + "@backstage/plugin-catalog-backend-module-gitlab": "0.8.3", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.21", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.12", + "@backstage/plugin-catalog-backend-module-ldap": "0.12.5", + "@backstage/plugin-catalog-backend-module-logs": "0.1.22", + "@backstage/plugin-catalog-backend-module-msgraph": "0.10.0", + "@backstage/plugin-catalog-backend-module-msgraph-incremental": "0.1.0", + "@backstage/plugin-catalog-backend-module-openapi": "0.2.22", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.22", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.20", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.12", + "@backstage/plugin-catalog-common": "1.1.10", + "@backstage/plugin-catalog-graph": "0.6.4", + "@backstage/plugin-catalog-import": "0.13.13", + "@backstage/plugin-catalog-node": "2.2.1", + "@backstage/plugin-catalog-react": "3.0.0", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.31", + "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.16", + "@backstage/plugin-config-schema": "0.1.80", + "@backstage/plugin-devtools": "0.1.39", + "@backstage/plugin-devtools-backend": "0.5.17", + "@backstage/plugin-devtools-common": "0.1.25", + "@backstage/plugin-devtools-react": "0.2.2", + "@backstage/plugin-events-backend": "0.6.2", + "@backstage/plugin-events-backend-module-aws-sqs": "0.4.22", + "@backstage/plugin-events-backend-module-azure": "0.2.31", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.31", + "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.12", + "@backstage/plugin-events-backend-module-gerrit": "0.2.31", + "@backstage/plugin-events-backend-module-github": "0.4.12", + "@backstage/plugin-events-backend-module-gitlab": "0.3.12", + "@backstage/plugin-events-backend-module-google-pubsub": "0.2.3", + "@backstage/plugin-events-backend-module-kafka": "0.3.4", + "@backstage/plugin-events-backend-test-utils": "0.1.55", + "@backstage/plugin-events-node": "0.4.22", + "@internal/plugin-todo-list": "1.0.51", + "@internal/plugin-todo-list-backend": "1.0.50", + "@internal/plugin-todo-list-common": "1.0.31", + "@backstage/plugin-gateway-backend": "1.1.5", + "@backstage/plugin-home": "0.9.6", + "@backstage/plugin-home-react": "0.1.38", + "@backstage/plugin-kubernetes": "0.12.19", + "@backstage/plugin-kubernetes-backend": "0.21.4", + "@backstage/plugin-kubernetes-cluster": "0.0.37", + "@backstage/plugin-kubernetes-common": "0.9.12", + "@backstage/plugin-kubernetes-node": "0.4.4", + "@backstage/plugin-kubernetes-react": "0.5.19", + "@backstage/plugin-mcp-actions-backend": "0.1.13", + "@backstage/plugin-mui-to-bui": "0.2.7", + "@backstage/plugin-notifications": "0.5.17", + "@backstage/plugin-notifications-backend": "0.6.5", + "@backstage/plugin-notifications-backend-module-email": "0.3.21", + "@backstage/plugin-notifications-backend-module-slack": "0.4.2", + "@backstage/plugin-notifications-common": "0.2.3", + "@backstage/plugin-notifications-node": "0.2.26", + "@backstage/plugin-org": "0.7.4", + "@backstage/plugin-org-react": "0.1.50", + "@backstage/plugin-permission-backend": "0.7.12", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.19", + "@backstage/plugin-permission-common": "0.9.9", + "@backstage/plugin-permission-node": "0.11.0", + "@backstage/plugin-permission-react": "0.5.1", + "@backstage/plugin-proxy-backend": "0.6.13", + "@backstage/plugin-proxy-node": "0.1.15", + "@backstage/plugin-scaffolder": "1.37.0", + "@backstage/plugin-scaffolder-backend": "4.0.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.2.21", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.3.6", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.21", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.21", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.23", + "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.21", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.21", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.21", + "@backstage/plugin-scaffolder-backend-module-github": "0.9.9", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.11.6", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.22", + "@backstage/plugin-scaffolder-backend-module-rails": "0.5.21", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.3.4", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.22", + "@backstage/plugin-scaffolder-common": "2.2.0", + "@backstage/plugin-scaffolder-node": "0.13.3", + "@backstage/plugin-scaffolder-node-test-utils": "0.3.11", + "@backstage/plugin-scaffolder-react": "2.0.0", + "@backstage/plugin-search": "1.7.4", + "@backstage/plugin-search-backend": "2.1.2", + "@backstage/plugin-search-backend-module-catalog": "0.3.15", + "@backstage/plugin-search-backend-module-elasticsearch": "1.8.3", + "@backstage/plugin-search-backend-module-explore": "0.3.14", + "@backstage/plugin-search-backend-module-pg": "0.5.55", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.20", + "@backstage/plugin-search-backend-module-techdocs": "0.4.14", + "@backstage/plugin-search-backend-node": "1.4.4", + "@backstage/plugin-search-common": "1.2.24", + "@backstage/plugin-search-react": "1.11.4", + "@backstage/plugin-signals": "0.0.31", + "@backstage/plugin-signals-backend": "0.3.15", + "@backstage/plugin-signals-node": "0.2.1", + "@backstage/plugin-signals-react": "0.0.22", + "@backstage/plugin-techdocs": "1.17.6", + "@backstage/plugin-techdocs-addons-test-utils": "2.0.5", + "@backstage/plugin-techdocs-backend": "2.2.0", "@backstage/plugin-techdocs-common": "0.1.1", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.35", - "@backstage/plugin-techdocs-node": "1.14.5", - "@backstage/plugin-techdocs-react": "1.3.10", - "@backstage/plugin-user-settings": "0.9.2", - "@backstage/plugin-user-settings-backend": "0.4.2", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.36", + "@backstage/plugin-techdocs-node": "1.15.0", + "@backstage/plugin-techdocs-react": "1.3.11", + "@backstage/plugin-user-settings": "0.9.3", + "@backstage/plugin-user-settings-backend": "0.4.3", "@backstage/plugin-user-settings-common": "0.1.0" }, - "changesets": [ - "add-missing-transitive-deps", - "add-service-unavailable-error-name", - "brave-groups-learn", - "chubby-candies-cry", - "clamp-react-aria-deps", - "deduplicate-joinpaths-routing", - "delegate-attach-mock-api-factory", - "extension-point-middleware-backend-app-api", - "extension-point-middleware-backend-defaults", - "fix-alter-target-nullability", - "fix-dialog-dark-theme-selector", - "fix-embedded-postgres-config-paths", - "fix-facets-perf-regression", - "fix-implicit-any-renderInTestApp", - "fix-scheduler-sleep-overflow", - "fix-tabs-active-indicator-disappearing", - "fix-widget-resize-after-edit", - "free-ways-flow", - "funny-areas-rescue", - "gold-drinks-poke", - "move-registermswtesthooks-to-test-utils", - "owner-column-cleanup", - "remove-duplicate-deps", - "remove-portable-schema-deprecated-prop", - "remove-unused-deps", - "remove-unused-getgithubintegrationconfig", - "replace-duplicate-error-utilities", - "shy-ways-lay", - "slack-scope-message-updates", - "ui-date-range-picker", - "upgrade-module-federation-v2", - "zod-v3-config-schema-docs", - "zod-v4-dep-bump" - ] + "changesets": [] } diff --git a/.changeset/remove-duplicate-deps.md b/.changeset/remove-duplicate-deps.md deleted file mode 100644 index d4fd31e037..0000000000 --- a/.changeset/remove-duplicate-deps.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/cli': patch -'@backstage/core-compat-api': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend-module-oidc-provider': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-notifications-backend-module-slack': patch ---- - -Removed duplicated entries that appeared in both `dependencies` and `devDependencies`. diff --git a/.changeset/remove-portable-schema-deprecated-prop.md b/.changeset/remove-portable-schema-deprecated-prop.md deleted file mode 100644 index aea8426f65..0000000000 --- a/.changeset/remove-portable-schema-deprecated-prop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': minor ---- - -**BREAKING**: Removed the deprecated property form of `PortableSchema.schema`. The `schema` member is now a plain method that must be called as `schema()` — direct property access like `schema.type` or `schema.properties` is no longer supported. diff --git a/.changeset/remove-unused-deps.md b/.changeset/remove-unused-deps.md deleted file mode 100644 index 028021bd28..0000000000 --- a/.changeset/remove-unused-deps.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-devtools-backend': patch -'@backstage/plugin-kubernetes-node': patch -'@backstage/plugin-notifications-common': patch -'@backstage/plugin-notifications-node': patch -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend-module-yeoman': patch -'@backstage/plugin-search-backend': patch -'@backstage/plugin-signals-node': patch -'@backstage/plugin-techdocs-react': patch -'@backstage/plugin-user-settings-backend': patch -'@techdocs/cli': patch ---- - -Removed unused dependencies that had no imports in source code. diff --git a/.changeset/remove-unused-getgithubintegrationconfig.md b/.changeset/remove-unused-getgithubintegrationconfig.md deleted file mode 100644 index 243fc8759c..0000000000 --- a/.changeset/remove-unused-getgithubintegrationconfig.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Internal refactor diff --git a/.changeset/replace-duplicate-error-utilities.md b/.changeset/replace-duplicate-error-utilities.md deleted file mode 100644 index 4e7d3d4318..0000000000 --- a/.changeset/replace-duplicate-error-utilities.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/repo-tools': patch -'@backstage/create-app': patch ---- - -Replaced internal error utilities with shared ones from `@backstage/cli-common`. diff --git a/.changeset/shy-ways-lay.md b/.changeset/shy-ways-lay.md deleted file mode 100644 index 2582c95944..0000000000 --- a/.changeset/shy-ways-lay.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-search-react': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-search': patch -'@backstage/plugin-app': patch -'@backstage/plugin-org': patch ---- - -Replaced old config schema values from existing extensions and blueprints. diff --git a/.changeset/slack-scope-message-updates.md b/.changeset/slack-scope-message-updates.md deleted file mode 100644 index 0bea25c1d8..0000000000 --- a/.changeset/slack-scope-message-updates.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-slack': patch ---- - -Added scope-based message update support. When a notification is re-sent with the same `scope` and `notification.updated` is set, the processor now calls `chat.update()` on the existing Slack message instead of sending a duplicate via `chat.postMessage()`. Message timestamps are persisted in a new `slack_message_timestamps` database table with automatic daily cleanup. The processor gracefully degrades to the previous behavior when no database is provided. diff --git a/.changeset/stitch-claim-transaction.md b/.changeset/stitch-claim-transaction.md new file mode 100644 index 0000000000..bd5fe2fbfc --- /dev/null +++ b/.changeset/stitch-claim-transaction.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fixed a race condition in the stitch queue and entity processing claim logic where `SELECT FOR UPDATE SKIP LOCKED` row locks were released before the subsequent timestamp bump, allowing multiple workers to claim the same rows. Both the select and update now run inside a single transaction for MySQL and PostgreSQL. diff --git a/.changeset/ui-date-range-picker.md b/.changeset/ui-date-range-picker.md deleted file mode 100644 index e69da8d7f9..0000000000 --- a/.changeset/ui-date-range-picker.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Added new `DateRangePicker` component — combines two date fields and a calendar popover for selecting a date range, built on React Aria with full keyboard and screen reader accessibility. Uses BUI design tokens throughout, including auto-incremented backgrounds via the bg consumer pattern. diff --git a/.changeset/upgrade-module-federation-v2.md b/.changeset/upgrade-module-federation-v2.md deleted file mode 100644 index 951f2e95e0..0000000000 --- a/.changeset/upgrade-module-federation-v2.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/cli-module-build': patch -'@backstage/frontend-dynamic-feature-loader': patch -'@backstage/module-federation-common': patch -'@backstage/backend-dynamic-feature-service': patch ---- - -Upgraded `@module-federation/enhanced`, `@module-federation/runtime`, and `@module-federation/sdk` from `^0.21.6` to `^2.3.3` to address known vulnerabilities. diff --git a/.changeset/zod-v3-config-schema-docs.md b/.changeset/zod-v3-config-schema-docs.md deleted file mode 100644 index 11fafd67d9..0000000000 --- a/.changeset/zod-v3-config-schema-docs.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Updated error messages and deprecation warnings to clarify that the `zod/v4` subpath export from the Zod v3 package is not supported by `configSchema`, since it does not include JSON Schema conversion. The `zod` dependency has been bumped to `^4.0.0`. diff --git a/.changeset/zod-v4-dep-bump.md b/.changeset/zod-v4-dep-bump.md deleted file mode 100644 index f9b298f8c0..0000000000 --- a/.changeset/zod-v4-dep-bump.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-app': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-search': patch -'@backstage/plugin-search-react': patch -'@backstage/plugin-org': patch ---- - -The `zod` dependency has been bumped from `^3.25.76 || ^4.0.0` to `^4.0.0`, since `configSchema` requires the full Zod v4 package for JSON Schema support. diff --git a/.cursor/rules/backstage-project.mdc b/.cursor/rules/backstage-project.mdc new file mode 120000 index 0000000000..b7e6491d3a --- /dev/null +++ b/.cursor/rules/backstage-project.mdc @@ -0,0 +1 @@ +../../AGENTS.md \ No newline at end of file diff --git a/.eslintignore b/.eslintignore index 5cfe8188d3..9b95ea30b1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,6 +8,7 @@ **/public/** **/microsite/** **/docs-ui/** +**/workspaces/** **/templates/** **/sample-templates/** playwright.config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7e5cc36bdf..735053f558 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -58,6 +58,7 @@ yarn.lock @backstage/maintainers @backst /plugins/catalog-backend-module-backstage-openapi @backstage/maintainers @backstage/openapi-tooling-maintainers /plugins/catalog-backend-module-gitea @backstage/maintainers @backstage/catalog-maintainers /plugins/catalog-backend-module-msgraph @backstage/maintainers @backstage/catalog-maintainers @pjungermann +/plugins/catalog-backend-module-msgraph-incremental @backstage/maintainers @backstage/catalog-maintainers /plugins/catalog-backend-module-puppetdb @backstage/maintainers @backstage/catalog-maintainers /plugins/catalog-graph @backstage/maintainers @backstage/catalog-maintainers @backstage/sda-se-reviewers /plugins/devtools @backstage/maintainers @awanlin @@ -85,6 +86,7 @@ yarn.lock @backstage/maintainers @backst /plugins/user-settings-common @backstage/maintainers @backstage/sda-se-reviewers /scripts @backstage/operations-maintainers +/workspaces/ui @backstage/design-system-maintainers /packages/backend-plugin-api/src/services/definitions/AuditorService.ts @backstage/maintainers @backstage/auditor-maintainers /packages/backend-defaults/src/entrypoints/auditor @backstage/maintainers @backstage/auditor-maintainers diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 353f878ae2..a4406cf623 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -75,6 +75,7 @@ codemod codemods codeowners codescene +Combobox composability composable config @@ -102,6 +103,7 @@ dayjs debounce debounced debounces +debouncing debuggability declaratively deduplicate @@ -256,6 +258,7 @@ LocalStack lockdown lockfile lockfiles +loopback lookbehind lookup lookups @@ -345,6 +348,7 @@ params parseable passthrough passwordless +patcher Patrik pattison Peloton diff --git a/.github/workflows/api-breaking-changes-comment.yml b/.github/workflows/api-breaking-changes-comment.yml index d416916bb0..b0f8f82a74 100644 --- a/.github/workflows/api-breaking-changes-comment.yml +++ b/.github/workflows/api-breaking-changes-comment.yml @@ -74,7 +74,7 @@ jobs: - name: Cache Comment if: ${{ steps.event.outputs.ACTION != 'closed' }} - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: comment.md key: ${{ steps.hash.outputs.COMMENT_FILE_HASH }} @@ -103,7 +103,7 @@ jobs: - name: Fetch cached Manifests File id: cache - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: comment.md key: ${{ needs.setup.outputs.comment-cache-key }} diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml index 53c90cb066..d8e2c9d2ba 100644 --- a/.github/workflows/api-breaking-changes.yml +++ b/.github/workflows/api-breaking-changes.yml @@ -47,7 +47,7 @@ jobs: cat ${{ github.event_path }} > event.json - name: Upload Artifacts - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: preview-spec path: | diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index 90b8ea9d16..121812000e 100644 --- a/.github/workflows/automate_area-labels.yml +++ b/.github/workflows/automate_area-labels.yml @@ -17,7 +17,7 @@ jobs: with: egress-policy: audit - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' sync-labels: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d35644e152..adf675bde9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: run: | mkdir -p ./context echo "${{ github.event.pull_request.number }}" > ./context/pr-number - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: matrix.node-version == '22.x' with: name: pr-context @@ -257,7 +257,7 @@ jobs: # Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds - name: restore backstage-cli cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/backstage-cli key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }} @@ -281,7 +281,7 @@ jobs: # Always save success cache even if there were failures, that way it can be used in re-triggered builds - name: save backstage-cli cache - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 if: always() with: path: .cache/backstage-cli diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index e07aa4409b..653b6e896b 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -72,7 +72,7 @@ jobs: # Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds - name: restore package-docs cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/package-docs key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-stable-${{ github.run_id }} @@ -83,7 +83,7 @@ jobs: run: yarn backstage-repo-tools package-docs - name: upload API reference - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: stable-reference path: type-docs/ @@ -92,7 +92,7 @@ jobs: # Always save success cache even if there were failures, that way it can be used in re-triggered builds - name: save package-docs cache - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 if: always() with: path: .cache/package-docs @@ -107,7 +107,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: stable-openapi-docs path: docs/**/api/**/* @@ -145,7 +145,7 @@ jobs: # Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds - name: restore package-docs cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/package-docs key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-${{ github.run_id }} @@ -156,7 +156,7 @@ jobs: run: yarn backstage-repo-tools package-docs - name: upload API reference - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: next-reference path: type-docs/ @@ -165,7 +165,7 @@ jobs: # Always save success cache even if there were failures, that way it can be used in re-triggered builds - name: save package-docs cache - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 if: always() with: path: .cache/package-docs @@ -175,7 +175,7 @@ jobs: run: yarn build-storybook - name: Upload Storybook - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: storybook path: dist-storybook @@ -191,7 +191,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: next-openapi-docs path: docs/**/api/**/* diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index fd92bf9b64..af0892d8a5 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -94,7 +94,7 @@ jobs: run: yarn backstage-cli config:check --lax - name: backstage-cli cache - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/backstage-cli key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }} @@ -118,8 +118,8 @@ jobs: yarn backstage-cli repo test --maxWorkers=3 --workerIdleMemoryLimit=1300M --coverage --success-cache --success-cache-dir .cache/backstage-cli env: BACKSTAGE_TEST_DISABLE_DOCKER: 1 - BACKSTAGE_TEST_DATABASE_postgres18_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres18.ports[5432] }} - BACKSTAGE_TEST_DATABASE_postgres14_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres14.ports[5432] }} + BACKSTAGE_TEST_DATABASE_POSTGRES18_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres18.ports[5432] }} + BACKSTAGE_TEST_DATABASE_POSTGRES14_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres14.ports[5432] }} BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING: redis://localhost:${{ job.services.redis.ports[6379] }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 4ba57ebb00..e4d1e35128 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -38,7 +38,7 @@ jobs: # These two steps add labels based on user input in the issue form - name: Parse issue form - uses: stefanbuck/github-issue-parser@10dcc54158ba4c137713d9d69d70a2da63b6bda3 # v3 + uses: stefanbuck/github-issue-parser@cb6e97157cbf851e3a393ff8d57c93a484cc323f # v3 id: issue-parser with: template-path: .github/ISSUE_TEMPLATE/.common.yaml diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 29c96b03d4..484a9e5c57 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -58,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: 'Upload artifact' - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: SARIF file path: results.sarif @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index 2b1dd1098f..805ac462ee 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -5,6 +5,10 @@ on: - '.github/workflows/sync_dependabot-changesets.yml' - '**/yarn.lock' +permissions: + contents: write + pull-requests: write + jobs: generate-changeset: runs-on: ubuntu-latest diff --git a/.github/workflows/sync_pull-requests-trigger.yml b/.github/workflows/sync_pull-requests-trigger.yml index fe87517bd1..57d20e2712 100644 --- a/.github/workflows/sync_pull-requests-trigger.yml +++ b/.github/workflows/sync_pull-requests-trigger.yml @@ -16,6 +16,11 @@ on: issue_comment: types: [created] +permissions: + actions: none + contents: none + pull-requests: none + jobs: trigger: if: > @@ -44,7 +49,7 @@ jobs: echo "$ACTOR" > ./context/actor echo "$ACTION" > ./context/action - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: pr-context path: context/ diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index 04495e606b..65312b6f64 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -5,6 +5,10 @@ on: - '.github/workflows/sync_renovate-changesets.yml' - '**/yarn.lock' +permissions: + contents: write + pull-requests: write + jobs: generate-changeset: runs-on: ubuntu-latest diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index b04c5b9ab7..db218b5d59 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -29,7 +29,7 @@ jobs: cache-prefix: ${{ runner.os }}-v22.x - name: Create Snyk report - uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master + uses: snyk/actions/node@9cf6ca713d71123d2d229cc3d7f145b96ea3c518 # master continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found with: args: > diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index a5f5707a52..5fa04f1c26 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Monitor and Synchronize Snyk Policies - uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master + uses: snyk/actions/node@9cf6ca713d71123d2d229cc3d7f145b96ea3c518 # master with: command: monitor args: > @@ -46,7 +46,7 @@ jobs: # Above we run the `monitor` command, this runs the `test` command which is # the one that generates the SARIF report that we can upload to GitHub. - name: Create Snyk report - uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master + uses: snyk/actions/node@9cf6ca713d71123d2d229cc3d7f145b96ea3c518 # master continue-on-error: true # To make sure that SARIF upload gets called with: args: > @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: sarif_file: snyk.sarif diff --git a/.github/workflows/verify_chromatic.yml b/.github/workflows/verify_chromatic.yml index 60cc1745d0..eea348d019 100644 --- a/.github/workflows/verify_chromatic.yml +++ b/.github/workflows/verify_chromatic.yml @@ -49,7 +49,7 @@ jobs: - name: Run Chromatic id: chromatic - uses: chromaui/action@f191a0224b10e1a38b2091cefb7b7a2337009116 # latest + uses: chromaui/action@e3eb8ec36101d8f0253c7c3ae66e5a2b4e2197ba # latest with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks @@ -82,7 +82,7 @@ jobs: - name: Post Chromatic Link in PR Comment if: github.event_name == 'pull_request' && steps.chromatic.outputs.url && github.event.pull_request.head.repo.full_name == github.repository - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3 with: message: | ## 🎨 Visual Testing with Chromatic diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index b9b1c734cf..816e657780 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 1a0eea2884..7b6d47232d 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -53,7 +53,7 @@ jobs: run: | mkdir -p ./context echo "${{ github.event.pull_request.number }}" > ./context/pr-number - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: matrix.node-version == '22.x' && github.event_name == 'pull_request' with: name: pr-context diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index 8578f0d41a..397c218413 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -77,7 +77,7 @@ jobs: # Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds - name: restore package-docs cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/package-docs key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-stable-${{ github.run_id }} @@ -88,14 +88,14 @@ jobs: run: yarn backstage-repo-tools package-docs - name: upload API reference - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: stable-reference path: type-docs/ # Always save success cache even if there were failures, that way it can be used in re-triggered builds - name: save package-docs cache - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 if: always() with: path: .cache/package-docs @@ -110,7 +110,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: stable-openapi-docs path: docs/**/api/**/* @@ -147,7 +147,7 @@ jobs: # Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds - name: restore package-docs cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .cache/package-docs key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-next-${{ github.run_id }} @@ -158,14 +158,14 @@ jobs: run: yarn backstage-repo-tools package-docs - name: upload API reference - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: next-reference path: type-docs/ # Always save success cache even if there were failures, that way it can be used in re-triggered builds - name: save package-docs cache - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 if: always() with: path: .cache/package-docs @@ -175,7 +175,7 @@ jobs: run: yarn build-storybook - name: Upload Storybook - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: storybook path: dist-storybook @@ -191,7 +191,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: next-openapi-docs path: docs/**/api/**/* diff --git a/.patches/pr-33908.txt b/.patches/pr-33908.txt deleted file mode 100644 index 5d0dd14d5a..0000000000 --- a/.patches/pr-33908.txt +++ /dev/null @@ -1 +0,0 @@ -Make TechDocs sidebar positioning configurable via CSS custom properties \ No newline at end of file diff --git a/.patches/pr-33952.txt b/.patches/pr-33952.txt deleted file mode 100644 index 3244566d2e..0000000000 --- a/.patches/pr-33952.txt +++ /dev/null @@ -1 +0,0 @@ -Bump zod dependency to v4 for packages using configSchema and clarify that zod/v4 subpath from v3 is not supported \ No newline at end of file diff --git a/.patches/pr-33975.txt b/.patches/pr-33975.txt deleted file mode 100644 index 5cc55be263..0000000000 --- a/.patches/pr-33975.txt +++ /dev/null @@ -1 +0,0 @@ -Clamp React Aria dependency ranges to patch-only updates to prevent unintended minor version upgrades \ No newline at end of file diff --git a/.patches/pr-33984.txt b/.patches/pr-33984.txt deleted file mode 100644 index 522b8121d9..0000000000 --- a/.patches/pr-33984.txt +++ /dev/null @@ -1 +0,0 @@ -Fix active tab indicator disappearing on uncontrolled Tabs in @backstage/ui \ No newline at end of file diff --git a/.patches/pr-34004.txt b/.patches/pr-34004.txt new file mode 100644 index 0000000000..506fd76855 --- /dev/null +++ b/.patches/pr-34004.txt @@ -0,0 +1 @@ +Preserve external hrefs in BUI link components under non-root base path \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 7269620fe6..5ed491cc25 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ .yarn dist microsite +workspaces docs-ui/.next docs-ui/public docs-ui/out diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 916c48951d..eb0b111bc9 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -50,26 +50,11 @@ export default definePreview({ dynamicTitle: true, }, }, - background: { - name: 'Background', - description: 'Global background for components', - defaultValue: 'app', - toolbar: { - icon: 'contrast', - items: [ - { value: 'app', title: 'App Background' }, - { value: 'neutral-1', title: 'Neutral 1 Background' }, - { value: 'neutral-2', title: 'Neutral 2 Background' }, - { value: 'neutral-3', title: 'Neutral 3 Background' }, - ], - }, - }, }, initialGlobals: { themeMode: 'light', themeName: 'backstage', - background: 'app', }, parameters: { @@ -143,7 +128,6 @@ export default definePreview({ globals.themeMode === 'light' ? themes.light : themes.dark; const selectedThemeMode = globals.themeMode || 'light'; const selectedThemeName = globals.themeName || 'backstage'; - const selectedBackground = globals.background || 'app'; const isFullscreen = context.parameters.layout === 'fullscreen'; useEffect(() => { @@ -155,15 +139,13 @@ export default definePreview({ document.body.removeAttribute('data-theme-mode'); document.body.removeAttribute('data-theme-name'); }; - }, [selectedTheme, selectedThemeName]); + }, [selectedThemeMode, selectedThemeName]); useEffect(() => { appThemeApi.setActiveThemeId(selectedThemeMode); }, [selectedThemeMode]); document.body.style.backgroundColor = 'var(--bui-bg-app)'; - document.body.style.padding = - isFullscreen && selectedBackground !== 'app' ? '1rem' : ''; const docsStoryElements = document.getElementsByClassName('docs-story'); Array.from(docsStoryElements).forEach(element => { (element as HTMLElement).style.backgroundColor = 'var(--bui-bg-app)'; @@ -174,18 +156,23 @@ export default definePreview({ {/* @ts-ignore */} - {Array.from({ - length: - selectedBackground === 'app' - ? 0 - : parseInt(selectedBackground.split('-')[1], 10), - }).reduce( - children => ( - - {children} - - ), - , + {selectedThemeName === 'spotify' ? ( + + + + ) : ( + )} diff --git a/.storybook/themes/spotify.css b/.storybook/themes/spotify.css index 30aa0274d0..7a34299817 100644 --- a/.storybook/themes/spotify.css +++ b/.storybook/themes/spotify.css @@ -190,10 +190,6 @@ .bui-Tag { border-radius: var(--bui-radius-full); } - - .bui-Container { - padding-inline: 0; - } } [data-theme-mode='light'][data-theme-name='spotify'] { @@ -243,24 +239,3 @@ --bui-ring: rgba(255, 255, 255, 0.2); } - -/* - * Plugin header (@backstage/ui) and story shell header — kept at the bottom of - * this file for easier scanning alongside other component overrides above. - */ -[data-theme-name='spotify'] { - .bui-PluginHeaderToolbar { - padding: 0; - height: 32px; - border: none; - background: none; - margin-bottom: var(--bui-space-2); - } - - .bui-PluginHeaderTabsWrapper { - padding: 0; - border: none; - background: none; - margin-left: -8px; - } -} diff --git a/AGENTS.md b/AGENTS.md index ae39378648..033a090d3f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,7 @@ +--- +alwaysApply: true +--- + Backstage is an open platform for building developer portals. This is a TypeScript monorepo using Yarn workspaces. ## Key Directories diff --git a/app-config.yaml b/app-config.yaml index 13cc5f2f4a..ea7bf95824 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -63,12 +63,10 @@ app: # - apis.plugin.graphiql.browse.gitlab: true # - graphiql-endpoint:graphiql/gitlab: true - - nav-item:search: false - - nav-item:user-settings: false - - nav-item:catalog - - nav-item:api-docs - - nav-item:scaffolder - - nav-item:app-visualizer + # Opt in to the experimental BUI scaffolder form theme + - sub-page:scaffolder/templates: + config: + enableBackstageUi: true # Pages - page:catalog: @@ -99,6 +97,16 @@ app: - custom: title: Custom + - sub-page:scaffolder/templates: + config: + groups: + - title: Recommended Services + filter: + spec.type: service + - title: Documentation + filter: + spec.type: documentation + # Entity page cards - entity-card:catalog/about: config: @@ -195,6 +203,7 @@ backend: pluginSources: - catalog - scaffolder + - search # See README.md in the proxy-backend plugin for information on the configuration format proxy: endpoints: @@ -275,6 +284,7 @@ catalog: pullRequestBranchName: backstage-integration rules: - allow: + - AiResource - Component - API - Resource @@ -343,15 +353,8 @@ scaffolder: auth: experimentalDynamicClientRegistration: enabled: true - allowedRedirectUriPatterns: - - cursor://* - - http://localhost:* - - http://127.0.0.1:* experimentalClientIdMetadataDocuments: enabled: true - allowedRedirectUriPatterns: - - http://127.0.0.1:* - - http://localhost:* ### Add auth.keyStore.provider to more granularly control how to store JWK data when running # the auth-backend. diff --git a/contrib/scripts/orphan-clean-up/OrphanCleanUp.ps1 b/contrib/scripts/orphan-clean-up/OrphanCleanUp.ps1 index 1eaaa2ab2c..378a992af6 100644 --- a/contrib/scripts/orphan-clean-up/OrphanCleanUp.ps1 +++ b/contrib/scripts/orphan-clean-up/OrphanCleanUp.ps1 @@ -1,6 +1,6 @@ <# .DESCRIPTION -Cleanes up orphaned entities for the provided Backstage URL, defaults to the local backend +Cleans up orphaned entities for the provided Backstage URL, defaults to the local backend #> param( [string]$backstageUrl = "http://localhost:7007" diff --git a/contrib/scripts/orphan-clean-up/orphan_cleanup.sh b/contrib/scripts/orphan-clean-up/orphan_cleanup.sh index 6ffe4737fb..a87b8de812 100755 --- a/contrib/scripts/orphan-clean-up/orphan_cleanup.sh +++ b/contrib/scripts/orphan-clean-up/orphan_cleanup.sh @@ -2,7 +2,7 @@ set -euo pipefail -# Cleanes up orphaned entities for the provided Backstage URL, defaults to the local backend +# Cleans up orphaned entities for the provided Backstage URL, defaults to the local backend BACKSTAGE_URL=${1:-'http://localhost:7007'} echo $BACKSTAGE_URL diff --git a/docs-ui/package.json b/docs-ui/package.json index 30b6d28b45..40c5b5bd6f 100644 --- a/docs-ui/package.json +++ b/docs-ui/package.json @@ -11,6 +11,7 @@ "sync:changelog:force": "node scripts/sync-changelog.mjs --force" }, "resolutions": { + "@remixicon/react": ">=4.6.0 <4.9.0", "@types/react": "19.2.10", "@types/react-dom": "19.2.3" }, @@ -22,13 +23,13 @@ "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "16.2.1", - "@remixicon/react": "^4.6.0", + "@remixicon/react": ">=4.6.0 <4.9.0", "@uiw/codemirror-themes": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", "clsx": "^2.1.1", "html-react-parser": "^5.2.5", "motion": "^12.4.1", - "next": "16.2.1", + "next": "16.2.3", "next-mdx-remote-client": "^2.1.2", "prop-types": "^15.8.1", "react": "19.2.4", @@ -44,7 +45,7 @@ "@types/react-dom": "19.2.3", "eslint": "^9", "eslint-config-next": "16.2.1", - "postcss": "^8.5.6", + "postcss": "^8.5.10", "postcss-import": "^16.1.1", "typescript": "^5", "unified": "^11.0.4" diff --git a/docs-ui/src/app/components/button/page.mdx b/docs-ui/src/app/components/button/page.mdx index 8183f8ca6c..765c3a0bef 100644 --- a/docs-ui/src/app/components/button/page.mdx +++ b/docs-ui/src/app/components/button/page.mdx @@ -29,7 +29,7 @@ import { } from './components'; export const reactAriaUrls = { - button: 'https://react-spectrum.adobe.com/react-aria/Button.html', + button: 'https://react-aria.adobe.com/Button', }; ( + +); + +export const WithLabelAndDescription = () => ( + +); + +export const Sizes = () => ( + + + + +); + +export const WithIcon = () => ( + } + style={{ width: 300 }} + /> +); + +export const Disabled = () => ( + +); + +export const AllowsCustomValue = () => ( + +); + +export const DisabledOption = () => ( + +); + +export const WithSections = () => ( + +); diff --git a/docs-ui/src/app/components/combobox/page.mdx b/docs-ui/src/app/components/combobox/page.mdx new file mode 100644 index 0000000000..d579e1ffbb --- /dev/null +++ b/docs-ui/src/app/components/combobox/page.mdx @@ -0,0 +1,153 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; +import { + Preview, + WithLabelAndDescription, + Sizes, + WithIcon, + Disabled, + DisabledOption, + AllowsCustomValue, + WithSections, +} from './components'; +import { comboboxPropDefs } from './props-definition'; +import { + optionPropDefs, + optionSectionPropDefs, +} from '../select/props-definition'; +import { + comboboxUsageSnippet, + comboboxDefaultSnippet, + comboboxDescriptionSnippet, + comboboxSizesSnippet, + comboboxDisabledSnippet, + comboboxResponsiveSnippet, + comboboxIconSnippet, + comboboxDisabledOptionsSnippet, + comboboxCustomValueSnippet, + comboboxSectionsSnippet, +} from './snippets'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { ComboboxDefinition } from '../../../utils/definitions'; + +export const reactAriaUrls = { + combobox: 'https://react-aria.adobe.com/ComboBox', +}; + + + +} + code={comboboxDefaultSnippet} +/> + +## Usage + + + +## API reference + + + + + +### Option types + +The `options` prop accepts an array containing either of the following shapes. + +#### `Option` + + + +#### `OptionSection` + + + +## Examples + +### Label and description + +} + code={comboboxDescriptionSnippet} +/> + +### Sizes + +} + code={comboboxSizesSnippet} +/> + +### With icon + +} + code={comboboxIconSnippet} +/> + +### Disabled + +} + code={comboboxDisabledSnippet} +/> + +### Disabled options + +} + code={comboboxDisabledOptionsSnippet} +/> + +### Custom values + +Allow the user to type a value that is not in the option list by setting `allowsCustomValue`. + +} + code={comboboxCustomValueSnippet} +/> + +### With sections + +Group options under section headings by passing objects with a `title` and a +nested `options` array. + +} + code={comboboxSectionsSnippet} +/> + +### Responsive + +Size can change at different breakpoints. + + + + + + diff --git a/docs-ui/src/app/components/combobox/props-definition.tsx b/docs-ui/src/app/components/combobox/props-definition.tsx new file mode 100644 index 0000000000..08499cc40b --- /dev/null +++ b/docs-ui/src/app/components/combobox/props-definition.tsx @@ -0,0 +1,113 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; +import { Chip } from '@/components/Chip'; + +export const comboboxPropDefs: Record = { + options: { + type: 'enum', + values: ['(Option | OptionSection)[]'], + description: ( + <> + Options to display in the dropdown. Pass Option objects + directly, or OptionSection objects to render grouped + options under section headings. + + ), + }, + allowsCustomValue: { + type: 'boolean', + default: 'false', + description: + 'When true, the typed text is accepted as the value on blur or Enter even if it does not match any option.', + }, + value: { + type: 'string', + description: 'Controlled selected value.', + }, + defaultValue: { + type: 'string', + description: 'Initial value for uncontrolled usage.', + }, + onChange: { + type: 'enum', + values: ['(value: Key | null) => void'], + description: 'Called when the selected option changes.', + }, + inputValue: { + type: 'string', + description: 'Controlled input text.', + }, + defaultInputValue: { + type: 'string', + description: 'Initial input text for uncontrolled usage.', + }, + onInputChange: { + type: 'enum', + values: ['(value: string) => void'], + description: 'Called when the input text changes.', + }, + label: { + type: 'string', + description: 'Visible label above the combobox.', + }, + secondaryLabel: { + type: 'string', + description: ( + <> + Secondary text shown next to the label. If not provided and isRequired + is true, displays Required. + + ), + }, + description: { + type: 'string', + description: 'Helper text displayed below the label.', + }, + placeholder: { + type: 'string', + description: 'Text shown when the input is empty.', + }, + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'small', + responsive: true, + description: 'Visual size of the combobox field.', + }, + icon: { + type: 'enum', + values: ['ReactNode'], + description: 'Icon displayed before the input.', + }, + onOpenChange: { + type: 'enum', + values: ['(isOpen: boolean) => void'], + description: 'Called when the dropdown opens or closes.', + }, + isDisabled: { + type: 'boolean', + description: 'Prevents user interaction when true.', + }, + disabledKeys: { + type: 'enum', + values: ['Iterable'], + description: 'Keys of options that should be disabled.', + }, + isRequired: { + type: 'boolean', + description: 'Marks the field as required for form validation.', + }, + isInvalid: { + type: 'boolean', + description: 'Displays the combobox in an error state.', + }, + name: { + type: 'string', + description: 'Form field name for form submission.', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/docs-ui/src/app/components/combobox/snippets.ts b/docs-ui/src/app/components/combobox/snippets.ts new file mode 100644 index 0000000000..28ca8c90af --- /dev/null +++ b/docs-ui/src/app/components/combobox/snippets.ts @@ -0,0 +1,114 @@ +export const comboboxUsageSnippet = `import { Combobox } from '@backstage/ui'; + +`; + +export const comboboxDefaultSnippet = ``; + +export const comboboxDescriptionSnippet = ``; + +export const comboboxIconSnippet = `} + options={[ ... ]} +/>`; + +export const comboboxSizesSnippet = ` + + +`; + +export const comboboxDisabledSnippet = ``; + +export const comboboxResponsiveSnippet = ``; + +export const comboboxDisabledOptionsSnippet = ``; + +export const comboboxCustomValueSnippet = ``; + +export const comboboxSectionsSnippet = ``; diff --git a/docs-ui/src/app/components/date-picker/components.tsx b/docs-ui/src/app/components/date-picker/components.tsx new file mode 100644 index 0000000000..699831c793 --- /dev/null +++ b/docs-ui/src/app/components/date-picker/components.tsx @@ -0,0 +1,36 @@ +'use client'; + +import { DatePicker } from '../../../../../packages/ui/src/components/DatePicker/DatePicker'; +import { Flex } from '../../../../../packages/ui/src/components/Flex/Flex'; +import { parseDate } from '@internationalized/date'; + +export const WithLabel = () => { + return ; +}; + +export const Sizes = () => { + return ( + + + + + ); +}; + +export const WithDefaultValue = () => { + return ( + + ); +}; + +export const Disabled = () => { + return ; +}; diff --git a/docs-ui/src/app/components/date-picker/page.mdx b/docs-ui/src/app/components/date-picker/page.mdx new file mode 100644 index 0000000000..d0e8cfdc11 --- /dev/null +++ b/docs-ui/src/app/components/date-picker/page.mdx @@ -0,0 +1,82 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { datePickerPropDefs } from './props-definition'; +import { + datePickerUsageSnippet, + withLabelSnippet, + sizesSnippet, + withDefaultValueSnippet, + disabledSnippet, +} from './snippets'; +import { WithLabel, Sizes, WithDefaultValue, Disabled } from './components'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { DatePickerDefinition } from '../../../utils/definitions'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; + +export const reactAriaUrls = { + datePicker: 'https://react-aria.adobe.com/DatePicker', +}; + + + +} + code={withLabelSnippet} +/> + +## Usage + + + +## API reference + + + + + +## Examples + +### Sizes + +} + code={sizesSnippet} + layout="side-by-side" +/> + +### With default value + +} + code={withDefaultValueSnippet} + layout="side-by-side" +/> + +### Disabled + +} + code={disabledSnippet} + layout="side-by-side" +/> + + + + diff --git a/docs-ui/src/app/components/date-picker/props-definition.tsx b/docs-ui/src/app/components/date-picker/props-definition.tsx new file mode 100644 index 0000000000..ccb5842b17 --- /dev/null +++ b/docs-ui/src/app/components/date-picker/props-definition.tsx @@ -0,0 +1,94 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; +import { Chip } from '@/components/Chip'; + +export const datePickerPropDefs: Record = { + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'small', + responsive: true, + description: ( + <> + Visual size of the picker. Use small for dense layouts,{' '} + medium for prominent fields. + + ), + }, + label: { + type: 'string', + description: 'Visible label displayed above the picker.', + }, + secondaryLabel: { + type: 'string', + description: ( + <> + Secondary text shown next to the label. If not provided and isRequired + is true, displays Required. + + ), + }, + description: { + type: 'string', + description: 'Help text displayed below the label.', + }, + value: { + type: 'enum', + values: ['DateValue'], + description: 'Controlled value of the date.', + }, + defaultValue: { + type: 'enum', + values: ['DateValue'], + description: 'Default value for uncontrolled usage.', + }, + onChange: { + type: 'enum', + values: ['(value: DateValue | null) => void'], + description: 'Handler called when the selected date changes.', + }, + granularity: { + type: 'enum', + values: ['day', 'hour', 'minute', 'second'], + default: 'day', + description: + 'Smallest unit displayed. Defaults to "day" for dates and "minute" for times.', + }, + minValue: { + type: 'enum', + values: ['DateValue'], + description: 'Minimum allowed date. Dates before this are disabled.', + }, + maxValue: { + type: 'enum', + values: ['DateValue'], + description: 'Maximum allowed date. Dates after this are disabled.', + }, + isDateUnavailable: { + type: 'enum', + values: ['(date: DateValue) => boolean'], + description: + 'Callback invoked for each calendar date. Return true to mark a date as unavailable.', + }, + name: { + type: 'string', + description: 'Form field name for the date, submitted as ISO 8601.', + }, + isRequired: { + type: 'boolean', + description: 'Whether the field is required for form submission.', + }, + isDisabled: { + type: 'boolean', + description: 'Whether the picker is disabled.', + }, + isReadOnly: { + type: 'boolean', + description: 'Whether the picker is read-only.', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/docs-ui/src/app/components/date-picker/snippets.ts b/docs-ui/src/app/components/date-picker/snippets.ts new file mode 100644 index 0000000000..9bab51bf45 --- /dev/null +++ b/docs-ui/src/app/components/date-picker/snippets.ts @@ -0,0 +1,25 @@ +export const datePickerUsageSnippet = `import { DatePicker } from '@backstage/ui'; + +`; + +export const withLabelSnippet = ``; + +export const sizesSnippet = ` + + +`; + +export const withDefaultValueSnippet = `import { parseDate } from '@internationalized/date'; + +`; + +export const disabledSnippet = ``; diff --git a/docs-ui/src/app/components/header/components.tsx b/docs-ui/src/app/components/header/components.tsx index 26dc715a5d..2a583e6c80 100644 --- a/docs-ui/src/app/components/header/components.tsx +++ b/docs-ui/src/app/components/header/components.tsx @@ -1,6 +1,8 @@ 'use client'; import { Header } from '../../../../../packages/ui/src/components/Header/Header'; +import { HeaderMetadataUsers } from '../../../../../packages/ui/src/components/Header/HeaderMetadataUsers'; +import { HeaderMetadataStatus } from '../../../../../packages/ui/src/components/Header/HeaderMetadataStatus'; import { Button } from '../../../../../packages/ui/src/components/Button/Button'; import { ButtonIcon } from '../../../../../packages/ui/src/components/ButtonIcon/ButtonIcon'; import { @@ -11,6 +13,29 @@ import { import { MemoryRouter } from 'react-router-dom'; import { RiMore2Line } from '@remixicon/react'; +const users = { + giles: { + name: 'Giles Peyton-Nicoll', + src: 'https://i.pravatar.cc/150?u=giles', + href: '/users/giles', + }, + alice: { + name: 'Alice Johnson', + src: 'https://i.pravatar.cc/150?u=alice42', + href: '/users/alice', + }, + bob: { + name: 'Bob Smith', + src: 'https://i.pravatar.cc/150?u=bob', + href: '/users/bob', + }, + carol: { + name: 'Carol Williams', + src: 'https://i.pravatar.cc/150?u=carol', + href: '/users/carol', + }, +}; + const tabs = [ { id: 'overview', label: 'Overview', href: '/overview' }, { id: 'checks', label: 'Checks', href: '/checks' }, @@ -29,12 +54,37 @@ const breadcrumbs = [ }, ]; +const tags = [ + { label: 'TypeScript' }, + { label: 'Platform', href: '/platform' }, +]; + +const metadataUsers = [ + { label: 'Type', value: 'website' }, + { + label: 'Status', + value: , + }, + { + label: 'Owner', + value: , + }, + { + label: 'Contributors', + value: ( + + ), + }, +]; + export const WithEverything = () => (
@@ -45,6 +95,84 @@ export const WithEverything = () => ( ); +export const WithMetadataUsers = () => ( + +
, + }, + { + label: 'Contributors', + value: ( + + ), + }, + ]} + /> + +); + +export const WithTags = () => ( + +
+ +); + +export const WithDescription = () => ( + +
+ +); + +export const WithMetadata = () => ( + +
+ +); + +export const WithMetadataStatus = () => ( + +
, + }, + { + label: 'Build', + value: ( + + ), + }, + { + label: 'Coverage', + value: , + }, + ]} + /> + +); + export const WithLongBreadcrumbs = () => (
diff --git a/docs-ui/src/app/components/header/page.mdx b/docs-ui/src/app/components/header/page.mdx index 9e02b70a70..107bf6d7f9 100644 --- a/docs-ui/src/app/components/header/page.mdx +++ b/docs-ui/src/app/components/header/page.mdx @@ -3,17 +3,28 @@ import { CodeBlock } from '@/components/CodeBlock'; import { Snippet } from '@/components/Snippet'; import { WithEverything, - WithLongBreadcrumbs, WithTabs, + WithTags, + WithDescription, + WithMetadata, + WithMetadataUsers, + WithMetadataStatus, WithCustomActions, WithMenu, } from './components'; -import { headerPagePropDefs } from './props-definition'; +import { + headerPagePropDefs, + headerMetadataUsersPropDefs, +} from './props-definition'; import { usage, defaultSnippet, withTabs, - withBreadcrumbs, + withTags, + withDescription, + withMetadata, + withMetadataUsers, + withMetadataStatus, withCustomActions, withMenu, } from './snippets'; @@ -24,7 +35,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; } code={defaultSnippet} /> @@ -39,11 +50,37 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ## Examples -### Breadcrumbs +### Tags -Labels are truncated at 240px. +Tags are rendered above the title. Each tag with an `href` renders as a link; tags without `href` render as plain text. Tags are separated by a small circle divider. -} code={withBreadcrumbs} /> +} code={withTags} /> + +### Description + +The description accepts a markdown string with support for inline links. Bold, italic, and block-level markdown are not rendered. + +} code={withDescription} /> + +### Metadata + +Key-value pairs displayed below the description. + +} code={withMetadata} /> + +### Metadata with users + +Use `HeaderMetadataUsers` as the metadata value to display users as avatars. A single user shows the avatar with their name beside it. Multiple users show a row of avatars — hover to reveal each name via tooltip. When a user has an `href`, the avatar and name become links. + +} code={withMetadataUsers} /> + + + +### Metadata with status + +Use `HeaderMetadataStatus` as the metadata value to display a status indicator. The dot colour is driven by the `color` prop which maps to BUI status tokens. Pass an `href` to make the label a link. + +} code={withMetadataStatus} /> ### Tabs diff --git a/docs-ui/src/app/components/header/props-definition.tsx b/docs-ui/src/app/components/header/props-definition.tsx index 0acc7d30ae..f4e7c2b670 100644 --- a/docs-ui/src/app/components/header/props-definition.tsx +++ b/docs-ui/src/app/components/header/props-definition.tsx @@ -5,6 +5,51 @@ export const headerPagePropDefs: Record = { type: 'string', description: 'Page heading displayed in the header.', }, + tags: { + type: 'complex', + description: + 'Items displayed above the title. Each tag renders as a link when href is provided, or as plain text otherwise. Tags are separated by a small circle divider.', + complexType: { + name: 'HeaderTag[]', + properties: { + label: { + type: 'string', + required: true, + description: 'Display text for the tag.', + }, + href: { + type: 'string', + required: false, + description: 'URL to navigate to when the tag is clicked.', + }, + }, + }, + }, + description: { + type: 'string', + description: + 'Markdown string rendered below the title. Only inline links are supported. Bold, italic, and block-level markdown are not rendered.', + }, + metadata: { + type: 'complex', + description: 'Key-value pairs displayed below the description.', + complexType: { + name: 'HeaderMetadataItem[]', + properties: { + label: { + type: 'string', + required: true, + description: 'The key label, displayed in secondary color.', + }, + value: { + type: 'string | ReactNode', + required: true, + description: + 'The value to display alongside the label. Pass a string for plain text or a ReactNode for custom content such as HeaderMetadataUsers.', + }, + }, + }, + }, customActions: { type: 'enum', values: ['ReactNode'], @@ -49,6 +94,7 @@ export const headerPagePropDefs: Record = { }, breadcrumbs: { type: 'complex', + deprecated: true, description: 'Breadcrumb trail displayed above the title.', complexType: { name: 'HeaderBreadcrumb[]', @@ -68,3 +114,33 @@ export const headerPagePropDefs: Record = { }, ...classNamePropDefs, }; + +export const headerMetadataUsersPropDefs: Record = { + users: { + type: 'complex', + description: + 'List of users to display. A single user shows the avatar with their name beside it. Multiple users show a row of avatars with names revealed on hover via tooltip.', + complexType: { + name: 'HeaderMetadataUser[]', + properties: { + name: { + type: 'string', + required: true, + description: + 'Display name shown beside the avatar (single) or in the tooltip (multiple).', + }, + src: { + type: 'string', + required: false, + description: 'URL for the avatar image.', + }, + href: { + type: 'string', + required: false, + description: + 'When provided, the avatar becomes a link and the name is rendered as a Link component.', + }, + }, + }, + }, +}; diff --git a/docs-ui/src/app/components/header/snippets.ts b/docs-ui/src/app/components/header/snippets.ts index 8dfef0e69e..ac38d6d7eb 100644 --- a/docs-ui/src/app/components/header/snippets.ts +++ b/docs-ui/src/app/components/header/snippets.ts @@ -2,15 +2,41 @@ export const usage = `import { Header } from '@backstage/ui';
`; -export const defaultSnippet = `
, + }, + { + label: 'Owner', + value: , + }, + { + label: 'Contributors', + value: ( + + ), + }, ]} tabs={[ { id: 'overview', label: 'Overview', href: '/overview' }, - { id: 'settings', label: 'Settings', href: '/settings' }, + { id: 'checks', label: 'Checks', href: '/checks' }, ]} customActions={ <> @@ -54,3 +80,70 @@ export const withMenu = `
} />`; + +export const withTags = `
`; + +export const withDescription = `
`; + +export const withMetadata = `
`; + +export const withMetadataStatus = `import { Header, HeaderMetadataStatus } from '@backstage/ui'; + +
, + }, + { + label: 'Build', + value: , + }, + { + label: 'Coverage', + value: , + }, + ]} +/>`; + +export const withMetadataUsers = `import { Header, HeaderMetadataUsers } from '@backstage/ui'; + +
, + }, + { + label: 'Contributors', + value: ( + + ), + }, + ]} +/>`; diff --git a/docs-ui/src/app/components/select/components.tsx b/docs-ui/src/app/components/select/components.tsx index 1cbc323b84..46cf6b0666 100644 --- a/docs-ui/src/app/components/select/components.tsx +++ b/docs-ui/src/app/components/select/components.tsx @@ -40,6 +40,33 @@ const skills = [ { value: 'swift', label: 'Swift' }, ]; +const sectionedFonts = [ + { + title: 'Serif Fonts', + options: [ + { value: 'times', label: 'Times New Roman' }, + { value: 'georgia', label: 'Georgia' }, + { value: 'garamond', label: 'Garamond' }, + ], + }, + { + title: 'Sans-Serif Fonts', + options: [ + { value: 'arial', label: 'Arial' }, + { value: 'helvetica', label: 'Helvetica' }, + { value: 'verdana', label: 'Verdana' }, + ], + }, + { + title: 'Monospace Fonts', + options: [ + { value: 'courier', label: 'Courier New' }, + { value: 'consolas', label: 'Consolas' }, + { value: 'fira', label: 'Fira Code' }, + ], + }, +]; + export const Preview = () => ( +); + +export const SearchableWithSections = () => ( + `; + +export const selectSectionsSnippet = ``; diff --git a/docs-ui/src/app/components/slider/page.mdx b/docs-ui/src/app/components/slider/page.mdx index c46185f9f6..19ffec08d0 100644 --- a/docs-ui/src/app/components/slider/page.mdx +++ b/docs-ui/src/app/components/slider/page.mdx @@ -28,7 +28,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; import { SliderDefinition } from '../../../utils/definitions'; export const reactAriaUrls = { - slider: 'https://react-spectrum.adobe.com/react-aria/Slider.html', + slider: 'https://react-aria.adobe.com/Slider', }; = { ), }, + searchDebounceMs: { + type: 'number', + description: ( + <> + Trailing-edge debounce delay (ms) applied to the search value before it + reaches searchFn. Defaults to 0 (no debounce). + Does not affect the controlled onSearchChange callback. + Only used with complete mode. + + ), + }, + filterDebounceMs: { + type: 'number', + description: ( + <> + Trailing-edge debounce delay (ms) applied to the filter value before it + reaches filterFn. Defaults to 0 (no debounce). + Does not affect the controlled onFilterChange callback. + Only used with complete mode. + + ), + }, }; export const useTableReturnPropDefs: Record = { diff --git a/docs-ui/src/app/tokens/page.mdx b/docs-ui/src/app/tokens/page.mdx index f359c10525..dbaab30252 100644 --- a/docs-ui/src/app/tokens/page.mdx +++ b/docs-ui/src/app/tokens/page.mdx @@ -264,6 +264,42 @@ pressed, and disabled variants for interactive states. +## Inherited background + +`--bui-bg-inherit` resolves to the bg color of the nearest enclosing element with a +`data-bg` attribute (set by `Box`, `Flex`, `Grid`, `Card`, `Accordion`, or any +element that explicitly sets `data-bg`). When no such ancestor exists it falls +back to `--bui-bg-app`. Use it from CSS when a sticky, fixed, or otherwise +overlapping element needs to match its surrounding bg without hardcoding a level. + + + + + + + Prop + Description + + + + + + --bui-bg-inherit + + + Resolves to the bg color of the nearest enclosing `data-bg` ancestor, + falling back to `--bui-bg-app`. + + + + + ## Solid background colors diff --git a/docs-ui/src/components/Chip/Chip.tsx b/docs-ui/src/components/Chip/Chip.tsx index b348b46c32..a1d9d75e62 100644 --- a/docs-ui/src/components/Chip/Chip.tsx +++ b/docs-ui/src/components/Chip/Chip.tsx @@ -4,12 +4,18 @@ import styles from './styles.module.css'; export const Chip = ({ children, head = false, + deprecated = false, }: { children: ReactNode; head?: boolean; + deprecated?: boolean; }) => { return ( - + {children} ); diff --git a/docs-ui/src/components/Chip/styles.module.css b/docs-ui/src/components/Chip/styles.module.css index d752ae2602..2446e46388 100644 --- a/docs-ui/src/components/Chip/styles.module.css +++ b/docs-ui/src/components/Chip/styles.module.css @@ -14,6 +14,11 @@ color: #2563eb; } +.deprecated { + background-color: #fff4e5; + color: #b45309; +} + [data-theme-mode='dark'] .chip { background-color: #2c2c2c; color: #fff; @@ -22,3 +27,8 @@ [data-theme-mode='dark'] .chip.head { background-color: #33405b; } + +[data-theme-mode='dark'] .chip.deprecated { + background-color: #3d2a10; + color: #fbbf24; +} diff --git a/docs-ui/src/components/PropsTable/PropsTable.tsx b/docs-ui/src/components/PropsTable/PropsTable.tsx index a8af2ad116..db5759d0e3 100644 --- a/docs-ui/src/components/PropsTable/PropsTable.tsx +++ b/docs-ui/src/components/PropsTable/PropsTable.tsx @@ -52,7 +52,12 @@ export const PropsTable = >({ switch (column) { case 'prop': - return {propName}; + return ( +
+ {propName} + {propData.deprecated && deprecated} +
+ ); case 'type': return ( diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index 55f10eba95..515deacb13 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -49,10 +49,19 @@ export const components: Page[] = [ title: 'CheckboxGroup', slug: 'checkbox-group', }, + { + title: 'Combobox', + slug: 'combobox', + status: 'new', + }, { title: 'Container', slug: 'container', }, + { + title: 'DatePicker', + slug: 'date-picker', + }, { title: 'DateRangePicker', slug: 'date-range-picker', diff --git a/docs-ui/src/utils/propDefs.ts b/docs-ui/src/utils/propDefs.ts index f714dd0d08..f92f1a37eb 100644 --- a/docs-ui/src/utils/propDefs.ts +++ b/docs-ui/src/utils/propDefs.ts @@ -44,6 +44,7 @@ export type PropDef = { required?: boolean; responsive?: boolean; description?: ReactNode; + deprecated?: boolean; }; export { breakpoints }; diff --git a/docs-ui/yarn.lock b/docs-ui/yarn.lock index 085b426dc6..b697e168fe 100644 --- a/docs-ui/yarn.lock +++ b/docs-ui/yarn.lock @@ -314,12 +314,12 @@ __metadata: languageName: node linkType: hard -"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.5.0": - version: 6.5.2 - resolution: "@codemirror/state@npm:6.5.2" +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.6.0": + version: 6.6.0 + resolution: "@codemirror/state@npm:6.6.0" dependencies: "@marijn/find-cluster-break": "npm:^1.0.0" - checksum: 10/5ccd3acb0c0a5b88e83fb91be39099fceb9f44a5047cc41a75d53f160e736851f65c8de40950b90c6519e6d2828e12f468db0af658dde30e938896f1c39eec91 + checksum: 10/5d624f3c8832b287d76ebb5f57c01327641875c12c58ada2a97f958dc4df8c3bb0a1ad08ed370300a4a929ee8d5c7f14a397449a0d075ac3129d60d85f077441 languageName: node linkType: hard @@ -336,14 +336,14 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.34.4, @codemirror/view@npm:^6.35.0": - version: 6.39.16 - resolution: "@codemirror/view@npm:6.39.16" + version: 6.41.1 + resolution: "@codemirror/view@npm:6.41.1" dependencies: - "@codemirror/state": "npm:^6.5.0" + "@codemirror/state": "npm:^6.6.0" crelt: "npm:^1.0.6" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/199576febda2a91fe7676b8708627ed2e38d7e964ec8258331422fe7c7f89003eee2de7dec828e09c046de005742fd476cae6ceebc7bd994744f771253bfcbf3 + checksum: 10/ab8156db1012f94ac39d603da4c397ab1de8877f941d0cf67f79cd09fffe9f39d5de8a10611a788ce9d5a88cad2633445880955fd0dc1ad67813cbf9be97774a languageName: node linkType: hard @@ -928,10 +928,10 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:16.2.1": - version: 16.2.1 - resolution: "@next/env@npm:16.2.1" - checksum: 10/c4f19f1767d7a1e8e9ff93cdee7e3b6a923d26d9d71f44124a797f03703ab9a18508b5ede997cc99d0307f2e0d0d1c426e9673a6c11ea10e170b87462a572236 +"@next/env@npm:16.2.3": + version: 16.2.3 + resolution: "@next/env@npm:16.2.3" + checksum: 10/30ed128d8ffae47e58732ee134b78da36e2d6942da7479ec5e640d205b7822224daf2f07d7a69352dc362908eb260fc9fa7eaba1ce5e6311abeacc6ffb0fe90a languageName: node linkType: hard @@ -961,58 +961,58 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-darwin-arm64@npm:16.2.1" +"@next/swc-darwin-arm64@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-darwin-arm64@npm:16.2.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-darwin-x64@npm:16.2.1" +"@next/swc-darwin-x64@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-darwin-x64@npm:16.2.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-linux-arm64-gnu@npm:16.2.1" +"@next/swc-linux-arm64-gnu@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-arm64-gnu@npm:16.2.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-linux-arm64-musl@npm:16.2.1" +"@next/swc-linux-arm64-musl@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-arm64-musl@npm:16.2.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-linux-x64-gnu@npm:16.2.1" +"@next/swc-linux-x64-gnu@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-x64-gnu@npm:16.2.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-linux-x64-musl@npm:16.2.1" +"@next/swc-linux-x64-musl@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-x64-musl@npm:16.2.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-win32-arm64-msvc@npm:16.2.1" +"@next/swc-win32-arm64-msvc@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-win32-arm64-msvc@npm:16.2.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:16.2.1": - version: 16.2.1 - resolution: "@next/swc-win32-x64-msvc@npm:16.2.1" +"@next/swc-win32-x64-msvc@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-win32-x64-msvc@npm:16.2.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1175,12 +1175,12 @@ __metadata: languageName: node linkType: hard -"@remixicon/react@npm:^4.6.0": - version: 4.9.0 - resolution: "@remixicon/react@npm:4.9.0" +"@remixicon/react@npm:>=4.6.0 <4.9.0": + version: 4.8.0 + resolution: "@remixicon/react@npm:4.8.0" peerDependencies: react: ">=18.2.0" - checksum: 10/3d8f1d86b2bb20ab5e44d15f18811e928b0886f7710eb7a1516afb9913ba72e46facec5dfee382825139d800bcbb6704c15d0c760d0f977c12257d4af8db3295 + checksum: 10/10241f2e07826ce7d595cf9687a35c96cc9cf9eb68a9431d7dfa1b9df479dbef302874d28c0502cee2a536cf34722de7c49ed12d10a2b071e4e42ba4a278c516 languageName: node linkType: hard @@ -1534,9 +1534,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.25.8": - version: 4.25.8 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.25.8" +"@uiw/codemirror-extensions-basic-setup@npm:4.25.9": + version: 4.25.9 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.25.9" dependencies: "@codemirror/autocomplete": "npm:^6.0.0" "@codemirror/commands": "npm:^6.0.0" @@ -1553,13 +1553,13 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 10/a8d83465f9f3393b6e95d98ae7f3616ad57f819bce64224831d3db19647524538fc013973074a63551afa69daad9a8ab05f2e5c7441db7e30e722495d7e991d3 + checksum: 10/bab06a40bdd8fb99a0af5115511cdb812c93aac2b93ccd8a02bdf8ea06098d6be2ce1302efc560a3b577171a5cd87d34c3215e523f21450ba100b147dfcb975c languageName: node linkType: hard "@uiw/codemirror-themes@npm:^4.23.7": - version: 4.25.8 - resolution: "@uiw/codemirror-themes@npm:4.25.8" + version: 4.25.9 + resolution: "@uiw/codemirror-themes@npm:4.25.9" dependencies: "@codemirror/language": "npm:^6.0.0" "@codemirror/state": "npm:^6.0.0" @@ -1568,19 +1568,19 @@ __metadata: "@codemirror/language": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 10/e9983b0f6e663ca200d36437b6b52b4061ce5ccefece6f738b15370a8a7ac6774e7139a82e9e28ae273692e25d0c0804693587ea0967e163a1c7ac8cf3859cd1 + checksum: 10/4a4fe7ae5f6c2bd37170b46c75ccabb67b47b7d3cee0de45c63fafe4f2b7569461b009e0ff5386480574e651627ed03c077833d53b6d3391102b79107ae39d15 languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.23.7": - version: 4.25.8 - resolution: "@uiw/react-codemirror@npm:4.25.8" + version: 4.25.9 + resolution: "@uiw/react-codemirror@npm:4.25.9" dependencies: "@babel/runtime": "npm:^7.18.6" "@codemirror/commands": "npm:^6.1.0" "@codemirror/state": "npm:^6.1.1" "@codemirror/theme-one-dark": "npm:^6.0.0" - "@uiw/codemirror-extensions-basic-setup": "npm:4.25.8" + "@uiw/codemirror-extensions-basic-setup": "npm:4.25.9" codemirror: "npm:^6.0.0" peerDependencies: "@babel/runtime": ">=7.11.0" @@ -1590,7 +1590,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/8c974e22dad1ad6231f33f7db42cd5b68caaf9bea545539b06b8a89dda3427eebadf47c8f48ee0d74cdf5a25000a8fcc02bac9fe560b624955eedf1f9bb47a85 + checksum: 10/02c6ababa9307cf10aee5b32db1a0e5885485960819d708cd154bc218cf4d8b182b5fb49fa7386014401d71c8391ce211b29b2de201ad1fdece2c1716d09a74d languageName: node linkType: hard @@ -2338,7 +2338,7 @@ __metadata: "@mdx-js/react": "npm:^3.1.0" "@next/mdx": "npm:16.2.1" "@octokit/rest": "npm:^22.0.1" - "@remixicon/react": "npm:^4.6.0" + "@remixicon/react": "npm:>=4.6.0 <4.9.0" "@shikijs/transformers": "npm:^3.13.0" "@types/mdx": "npm:^2.0.13" "@types/node": "npm:^22.13.14" @@ -2351,9 +2351,9 @@ __metadata: eslint-config-next: "npm:16.2.1" html-react-parser: "npm:^5.2.5" motion: "npm:^12.4.1" - next: "npm:16.2.1" + next: "npm:16.2.3" next-mdx-remote-client: "npm:^2.1.2" - postcss: "npm:^8.5.6" + postcss: "npm:^8.5.10" postcss-import: "npm:^16.1.1" prop-types: "npm:^15.8.1" react: "npm:19.2.4" @@ -3103,12 +3103,12 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^12.35.2": - version: 12.35.2 - resolution: "framer-motion@npm:12.35.2" +"framer-motion@npm:^12.38.0": + version: 12.38.0 + resolution: "framer-motion@npm:12.38.0" dependencies: - motion-dom: "npm:^12.35.2" - motion-utils: "npm:^12.29.2" + motion-dom: "npm:^12.38.0" + motion-utils: "npm:^12.36.0" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -3121,7 +3121,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/10af699ff1e35a166ef60ceab464479b81624ef74de3ec9e11b427f86bd7bf2c8c8a9f24fb0646288b2d4b0c1b219203da351821fc568c7b91c6821594af4a3f + checksum: 10/4d529d1648a8e31ec9859e7ff1296b7e4ef0028eb09cbc7d626068766ab53e486038b431fac33b1438a1cc076a244e6843c5a8c0f38442885832308452b4b25e languageName: node linkType: hard @@ -4500,27 +4500,27 @@ __metadata: languageName: node linkType: hard -"motion-dom@npm:^12.35.2": - version: 12.35.2 - resolution: "motion-dom@npm:12.35.2" +"motion-dom@npm:^12.38.0": + version: 12.38.0 + resolution: "motion-dom@npm:12.38.0" dependencies: - motion-utils: "npm:^12.29.2" - checksum: 10/dd009e58b178dd80b123a86199ae78ecd6b2fc6c8e03464b2daf43b4218dfcc36042ec0af8fad2c6c157198f56849f90dc033b58f46478b45fbaeaefcc2710ad + motion-utils: "npm:^12.36.0" + checksum: 10/78c040b46d93273932cf80c70e39845be5a442dcaf18d4345b45a9193de9dfa87c885b609943cb652115e4eac5d46ef40b452185073dd43fc328b134f9975e90 languageName: node linkType: hard -"motion-utils@npm:^12.29.2": - version: 12.29.2 - resolution: "motion-utils@npm:12.29.2" - checksum: 10/ae5f9be58c07939af72334894ed1a18653d724946182a718dc3d11268ef26e63804c3f16dee5a6110596d4406b539c4513822b74f86adebef9488601c34b18b7 +"motion-utils@npm:^12.36.0": + version: 12.36.0 + resolution: "motion-utils@npm:12.36.0" + checksum: 10/c4a2a7ffac48ca44082d6d31b115f245025060a7e69d70dac062646d8f96c39e5662a7c8a51f255566fdf8e719ef1269a8e9aa3a04fc263bb65b5a7b61331901 languageName: node linkType: hard "motion@npm:^12.4.1": - version: 12.35.2 - resolution: "motion@npm:12.35.2" + version: 12.38.0 + resolution: "motion@npm:12.38.0" dependencies: - framer-motion: "npm:^12.35.2" + framer-motion: "npm:^12.38.0" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -4533,7 +4533,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/3d99a53816634cbee1b38ed8a9a5d88bafbd29eb3bc02e78fc741c604972b4b88d317cf374bba30a1486f727bb1657ef8826f83e669a3b04fd1ec3ef75bfb62d + checksum: 10/d7ae2ba3cc112c4467822956b92065239640b9c62204d3bee1780da9fc0147185373534138d39975e82bf73b5f1b28d3fb3581031e4e7e0cfb230472767bd10d languageName: node linkType: hard @@ -4587,19 +4587,19 @@ __metadata: languageName: node linkType: hard -"next@npm:16.2.1": - version: 16.2.1 - resolution: "next@npm:16.2.1" +"next@npm:16.2.3": + version: 16.2.3 + resolution: "next@npm:16.2.3" dependencies: - "@next/env": "npm:16.2.1" - "@next/swc-darwin-arm64": "npm:16.2.1" - "@next/swc-darwin-x64": "npm:16.2.1" - "@next/swc-linux-arm64-gnu": "npm:16.2.1" - "@next/swc-linux-arm64-musl": "npm:16.2.1" - "@next/swc-linux-x64-gnu": "npm:16.2.1" - "@next/swc-linux-x64-musl": "npm:16.2.1" - "@next/swc-win32-arm64-msvc": "npm:16.2.1" - "@next/swc-win32-x64-msvc": "npm:16.2.1" + "@next/env": "npm:16.2.3" + "@next/swc-darwin-arm64": "npm:16.2.3" + "@next/swc-darwin-x64": "npm:16.2.3" + "@next/swc-linux-arm64-gnu": "npm:16.2.3" + "@next/swc-linux-arm64-musl": "npm:16.2.3" + "@next/swc-linux-x64-gnu": "npm:16.2.3" + "@next/swc-linux-x64-musl": "npm:16.2.3" + "@next/swc-win32-arm64-msvc": "npm:16.2.3" + "@next/swc-win32-x64-msvc": "npm:16.2.3" "@swc/helpers": "npm:0.5.15" baseline-browser-mapping: "npm:^2.9.19" caniuse-lite: "npm:^1.0.30001579" @@ -4643,7 +4643,7 @@ __metadata: optional: true bin: next: dist/bin/next - checksum: 10/319c0b18173a90e53b5e5ffafa8a8fecb7cc340b77728796743edd996c7ee7652201892bff60c32f6a3b75abdff1449b77f13f6fab8fd56d4f9da47cf0fb9299 + checksum: 10/5164885daacbb36a771380e1b5efba524863e1bdf2b5a6c80413cbf1e3ab4e8ddab5716cd91ff94ca5c5c5deb2a12d1312d6d6ae994e16ebfa985fdda6134bc6 languageName: node linkType: hard @@ -4857,9 +4857,9 @@ __metadata: linkType: hard "picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc + version: 2.3.2 + resolution: "picomatch@npm:2.3.2" + checksum: 10/b788ef8148a2415b9dec12f0bb350ae6a5830f8f1950e472abc2f5225494debf7d1b75eb031df0ceaea9e8ec3e7bad599e8dbf3c60d61b42be429ba41bff4426 languageName: node linkType: hard @@ -4915,14 +4915,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.6": - version: 8.5.8 - resolution: "postcss@npm:8.5.8" +"postcss@npm:^8.5.10": + version: 8.5.10 + resolution: "postcss@npm:8.5.10" dependencies: nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/cbacbfd7f767e2c820d4bf09a3a744834dd7d14f69ff08d1f57b1a7defce9ae5efcf31981890d9697a972a64e9965de677932ef28e4c8ba23a87aad45b82c459 + checksum: 10/7eac6169e535b63c8412e94d4f6047fc23efa3e9dde804b541940043c831b25f1cd867d83cd2c4371ad2450c8abcb42c208aa25668c1f0f3650d7f72faf711a8 languageName: node linkType: hard @@ -6241,11 +6241,11 @@ __metadata: linkType: hard "yaml@npm:^2.0.0": - version: 2.8.1 - resolution: "yaml@npm:2.8.1" + version: 2.8.3 + resolution: "yaml@npm:2.8.3" bin: yaml: bin.mjs - checksum: 10/eae07b3947d405012672ec17ce27348aea7d1fa0534143355d24a43a58f5e05652157ea2182c4fe0604f0540be71f99f1173f9d61018379404507790dff17665 + checksum: 10/ecad41d39d34fae5cc17ea2d4b7f7f55faacd45cbce8983ba22d48d1ed1a92ed242ea49ea813a79ac39a69f75f9c5a03e7b5395fd954d55476f25e21a47c141d languageName: node linkType: hard diff --git a/docs/.well-known/skills/app-frontend-system-migration/SKILL.md b/docs/.well-known/skills/app-frontend-system-migration/SKILL.md index 0bfbf0714c..9bb12bd700 100644 --- a/docs/.well-known/skills/app-frontend-system-migration/SKILL.md +++ b/docs/.well-known/skills/app-frontend-system-migration/SKILL.md @@ -60,7 +60,7 @@ Even with feature discovery enabled, you can disable specific extensions via con app: extensions: - page:techdocs: false - - nav-item:search: false + - page:search: false ``` ### How Discovery Works with Manual Imports diff --git a/docs/.well-known/skills/index.json b/docs/.well-known/skills/index.json index e66c7ea791..650166f944 100644 --- a/docs/.well-known/skills/index.json +++ b/docs/.well-known/skills/index.json @@ -19,6 +19,11 @@ "name": "plugin-full-frontend-system-migration", "description": "Fully migrate a Backstage plugin to the new frontend system, dropping all old system support. Use this skill for internal plugins that only need to run in a single app, or when you are ready to remove backward compatibility entirely.", "files": ["SKILL.md"] + }, + { + "name": "plugin-analytics-instrumentation", + "description": "Instrument a Backstage frontend plugin with analytics events using the Backstage Analytics API. Use this skill when adding, reviewing, or extending event capture (captureEvent, AnalyticsContext) in plugin components, deciding whether an interaction warrants an event, or writing tests for analytics behavior.", + "files": ["SKILL.md"] } ] } diff --git a/docs/.well-known/skills/mui-to-bui-migration/SKILL.md b/docs/.well-known/skills/mui-to-bui-migration/SKILL.md index 94e2bcfdcd..80ea04ba9c 100644 --- a/docs/.well-known/skills/mui-to-bui-migration/SKILL.md +++ b/docs/.well-known/skills/mui-to-bui-migration/SKILL.md @@ -5,8 +5,8 @@ description: Migrate Backstage plugins from Material-UI (MUI) to Backstage UI (B # MUI to BUI Migration Skill -This skill helps migrate Backstage plugins from Material-UI (@material-ui/core, @material-ui/icons) to Backstage UI ( -@backstage/ui). +This skill helps migrate Backstage plugins from Material-UI (@material-ui/core, @material-ui/icons) to +Backstage UI (@backstage/ui). ## Prerequisites @@ -19,6 +19,7 @@ Before starting migration: ``` 2. Add the CSS import to your root file (typically `src/index.ts` or app entry point): + ```typescript import '@backstage/ui/css/styles.css'; ``` @@ -38,11 +39,14 @@ Before starting migration: - `Accordion` - Collapsible content panels (`Accordion`, `AccordionTrigger`, `AccordionPanel`, `AccordionGroup`) - `Alert` - Alert/notification banners (`status`, `title`, `description`) - `Avatar` - User/entity avatars +- `Badge` - Inline badge/label with optional icon (`size`, `icon`) - `Button` - Action buttons (`variant="primary"`, `variant="secondary"`, `variant="tertiary"`, `isDisabled`, `destructive`, `loading`) - `ButtonIcon` - Icon-only buttons (`icon`, `onPress`, `variant`) - `ButtonLink` - Link styled as button - `Card` - Content cards (`Card`, `CardHeader`, `CardBody`, `CardFooter`) - `Checkbox` - Checkbox input +- `CheckboxGroup` - Grouped checkboxes with shared label (`label`, `orientation`, `isRequired`) +- `DateRangePicker` - Date range input field (`label`, `value`, `onChange`) - `Dialog` - Modal dialogs (`DialogTrigger`, `Dialog`, `DialogHeader`, `DialogBody`, `DialogFooter`) - `FieldLabel` - Form field label with description and secondary label - `Header` - Page headers with breadcrumbs and tabs @@ -57,6 +61,7 @@ Before starting migration: - `SearchField` - Search input - `Select` - Dropdown select (single and multiple selection modes) - `Skeleton` - Loading skeleton +- `Slider` - Range slider input (`label`, `minValue`, `maxValue`, `step`) - `Switch` - Toggle switch - `Table` - Data tables (with `useTable` hook for data management) - `TablePagination` - Standalone pagination component @@ -103,9 +108,9 @@ Create a `.module.css` file alongside your component using BUI CSS variables. **Before (MUI `makeStyles`):** -```typescript +```tsx // MyComponent.tsx -import {makeStyles, Theme} from '@material-ui/core/styles'; +import { makeStyles, Theme } from '@material-ui/core/styles'; const useStyles = makeStyles((theme: Theme) => ({ container: { @@ -130,18 +135,16 @@ const useStyles = makeStyles((theme: Theme) => ({ function MyComponent() { const classes = useStyles(); return ( -
- Title < /Typography> - < div - className = {classes.listItem} > -
- +
+ Title +
+
+ +
+ Content +
- < span > Content < /span> - < /div> - < /div> -) - ; + ); } ``` @@ -177,27 +180,24 @@ function MyComponent() { } ``` -```typescript +```tsx // MyComponent.tsx -import {Box, Text} from '@backstage/ui'; -import {RiSomeIcon} from '@remixicon/react'; +import { Box, Text } from '@backstage/ui'; +import { RiSomeIcon } from '@remixicon/react'; import styles from './MyComponent.module.css'; function MyComponent() { return ( - - Title < /Text> - < div - className = {styles.listItem} > -
- - < /div> - < span > Content < /span> - < /div> - < /Box> -) - ; + + Title +
+
+ +
+ Content +
+
+ ); } ``` @@ -205,38 +205,27 @@ function MyComponent() { **Before (MUI Box with display prop):** -```typescript +```tsx - - {children} - < /Box> - < /Box> + + {children} + + ``` **After (BUI `Flex` component):** -```typescript - - -{ - children -} +```tsx + + + {children} + -< /Flex> ``` Note: BUI `Flex` uses `justify="between"` not `justify="space-between"`. @@ -245,70 +234,40 @@ Note: BUI `Flex` uses `justify="between"` not `justify="space-between"`. **Before (MUI Grid):** -```typescript - - - {content} - < /Grid> - < /Grid> +```tsx + + + {content} + + ``` **After (BUI Grid):** -```typescript - - -{ - content -} - -< /Grid.Root> +```tsx + + {content} + ``` ### 5. Typography to Text **Before (MUI Typography):** -```typescript - Heading < /Typography> - < Typography -variant = "h6" > Subheading < /Typography> - < Typography -variant = "body1" > Body -text < /Typography> -< Typography -variant = "body2" -color = "textSecondary" > Secondary -text < /Typography> +```tsx +Heading +Subheading +Body text +Secondary text ``` **After (BUI Text):** -```typescript - Heading < /Text> - < Text -variant = "title-small" > Subheading < /Text> - < Text -variant = "body-medium" > Body -text < /Text> -< Text -variant = "body-small" -color = "secondary" > Secondary -text < /Text> +```tsx +Heading +Subheading +Body text +Secondary text ``` Valid Text variants: `title-large`, `title-medium`, `title-small`, `title-x-small`, `body-large`, `body-medium`, @@ -318,19 +277,17 @@ Valid Text variants: `title-large`, `title-medium`, `title-small`, `title-x-smal **Before (MUI Tooltip):** -```typescript -import {Tooltip, Typography} from '@material-ui/core'; +```tsx +import { Tooltip, Typography } from '@material-ui/core'; - Tooltip -content < /Typography>}> -< span > Hover -me < /span> -< /Tooltip>; +Tooltip content}> + Hover me +; ``` **After (BUI TooltipTrigger pattern):** -```typescript +```tsx import { Tooltip, TooltipTrigger, Text } from '@backstage/ui'; @@ -343,26 +300,23 @@ import { Tooltip, TooltipTrigger, Text } from '@backstage/ui'; **Before (MUI Dialog):** -```typescript -import {Dialog, DialogTitle, DialogActions, Button} from '@material-ui/core'; +```tsx +import { Dialog, DialogTitle, DialogActions, Button } from '@material-ui/core'; - -Title < /DialogTitle> -< DialogActions > - + + +; ``` **After (BUI Dialog):** -```typescript +```tsx import { Dialog, DialogTrigger, @@ -373,78 +327,58 @@ import { -{ - if (!open) onClose(); -} -} -> -Title < /DialogHeader> -< DialogFooter > - + + + +; ``` ### 8. Button Changes **Before (MUI Button):** -```typescript - + + ``` **After (BUI Button):** -```typescript - +} + variant="secondary" +/> ``` ### 9. TextField Changes **Before (MUI TextField):** -```typescript +```tsx - - - + + + + - < TabPanel -value = "tab1" > Content -1 < /TabPanel> -< TabPanel -value = "tab2" > Content -2 < /TabPanel> -< /TabContext>; + Content 1 + Content 2 +; ``` **After (BUI Tabs):** -```typescript -import {Tabs, TabList, Tab, TabPanel} from '@backstage/ui'; +```tsx +import { Tabs, TabList, Tab, TabPanel } from '@backstage/ui'; - - - Tab -1 < /Tab> -< Tab -id = "tab2" > Tab -2 < /Tab> -< /TabList> -< TabPanel -id = "tab1" > Content -1 < /TabPanel> -< TabPanel -id = "tab2" > Content -2 < /TabPanel> -< /Tabs>; + + + Tab 1 + Tab 2 + + Content 1 + Content 2 +; ``` ### 11. Menu Pattern **Before (MUI Menu):** -```typescript +```tsx import {IconButton, Popover, MenuList, MenuItem} from '@material-ui/core'; import MoreVertIcon from '@material-ui/icons/MoreVert'; - - < Popover -open = {open} -anchorEl = {anchorEl} -onClose = {handleClose} > - - Action < /MenuItem> - < /MenuList> - < /Popover> + + + + + + Action + + ``` **After (BUI Menu):** -```typescript -import {ButtonIcon, Menu, MenuItem, MenuTrigger} from '@backstage/ui'; -import {RiMore2Line} from '@remixicon/react'; +```tsx +import { ButtonIcon, Menu, MenuItem, MenuTrigger } from '@backstage/ui'; +import { RiMore2Line } from '@remixicon/react'; - -} -variant = "secondary" / > - - Action < /MenuItem> - < /Menu> - < /MenuTrigger>; + } variant="secondary" /> + + Action + +; ``` ### 12. List to BUI List **Before (MUI List):** -```typescript +```tsx import { List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; @@ -570,7 +487,7 @@ import { List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; **After (BUI List):** -```typescript +```tsx import { List, ListRow } from '@backstage/ui'; import { RiSomeIcon } from '@remixicon/react'; @@ -587,7 +504,7 @@ Note: `ListRow` supports `icon`, `description`, `menuItems`, and `customActions` **Before (MUI Chip):** -```typescript +```tsx import { Chip } from '@material-ui/core'; ; @@ -595,17 +512,17 @@ import { Chip } from '@material-ui/core'; **After (BUI Tag):** -```typescript -import {Tag} from '@backstage/ui'; +```tsx +import { Tag } from '@backstage/ui'; - Category < /Tag>; +Category; ``` ### 14. Alert Pattern **Before (MUI Alert):** -```typescript +```tsx import { Alert, AlertTitle } from '@material-ui/lab'; @@ -616,7 +533,7 @@ import { Alert, AlertTitle } from '@material-ui/lab'; **After (BUI Alert):** -```typescript +```tsx import { Alert } from '@backstage/ui'; - + + ``` **After (Remix Icons):** -```typescript +```tsx import {RiCloseLine, RiSearchLine} from '@remixicon/react'; - - + + ``` Common icon mappings: @@ -683,6 +599,239 @@ Common icon mappings: Find more icons at: https://remixicon.com/ +### 16. Paper to Card + +**Before (MUI Paper):** + +```tsx +import { Paper, Typography } from '@material-ui/core'; + + + Title + Body content +; +``` + +**After (BUI Card):** + +```tsx +import { Card, CardHeader, CardBody, Text } from '@backstage/ui'; + + + Title + + Body content + +; +``` + +### 17. Select + +**Before (MUI Select):** + +```tsx +import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core'; + + + Framework + +; +``` + +**After (BUI Select):** + +```tsx +import { Select } from '@backstage/ui'; + + + + + ); +} diff --git a/packages/ui/src/components/Combobox/ComboboxListBox.tsx b/packages/ui/src/components/Combobox/ComboboxListBox.tsx new file mode 100644 index 0000000000..ae65bd8da3 --- /dev/null +++ b/packages/ui/src/components/Combobox/ComboboxListBox.tsx @@ -0,0 +1,90 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { + ListBox, + ListBoxItem, + ListBoxSection, + Header, + Text, +} from 'react-aria-components'; +import { RiCheckLine } from '@remixicon/react'; +import { useDefinition } from '../../hooks/useDefinition'; +import { + ComboboxListBoxDefinition, + ComboboxListBoxItemDefinition, + ComboboxSectionDefinition, +} from './definition'; +import type { Option, OptionSection, ComboboxListBoxOwnProps } from './types'; + +const NoResults = () => { + const { ownProps } = useDefinition(ComboboxListBoxDefinition, {}); + const { classes } = ownProps; + + return
No results found.
; +}; + +function ComboboxItem({ option }: { option: Option }) { + const { ownProps } = useDefinition(ComboboxListBoxItemDefinition, {}); + const { classes } = ownProps; + + return ( + +
+
+ + {option.label} + +
+ ); +} + +function ComboboxSectionItems({ section }: { section: OptionSection }) { + const { ownProps } = useDefinition(ComboboxSectionDefinition, {}); + const { classes } = ownProps; + + return ( + +
{section.title}
+ {section.options.map(option => ( + + ))} +
+ ); +} + +export function ComboboxListBox(props: ComboboxListBoxOwnProps) { + const { ownProps } = useDefinition(ComboboxListBoxDefinition, props); + const { classes, options } = ownProps; + + return ( + }> + {options?.map(item => + 'options' in item ? ( + + ) : ( + + ), + )} + + ); +} diff --git a/packages/ui/src/components/Combobox/definition.ts b/packages/ui/src/components/Combobox/definition.ts new file mode 100644 index 0000000000..06143e7c05 --- /dev/null +++ b/packages/ui/src/components/Combobox/definition.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { defineComponent } from '../../hooks/useDefinition'; +import type { + ComboboxOwnProps, + ComboboxInputOwnProps, + ComboboxListBoxOwnProps, + ComboboxListBoxItemOwnProps, + ComboboxSectionOwnProps, +} from './types'; +import styles from './Combobox.module.css'; + +/** + * Component definition for Combobox + * @public + */ +export const ComboboxDefinition = defineComponent()({ + styles, + classNames: { + root: 'bui-Combobox', + popover: 'bui-ComboboxPopover', + }, + propDefs: { + icon: {}, + size: { dataAttribute: true, default: 'small' }, + options: {}, + placeholder: {}, + label: {}, + secondaryLabel: {}, + description: {}, + isRequired: {}, + className: {}, + }, +}); + +/** + * Component definition for ComboboxInput + * @public + */ +export const ComboboxInputDefinition = defineComponent()( + { + styles, + classNames: { + root: 'bui-ComboboxInput', + icon: 'bui-ComboboxInputIcon', + input: 'bui-ComboboxInputField', + chevron: 'bui-ComboboxInputChevron', + }, + bg: 'consumer', + propDefs: { + icon: {}, + placeholder: {}, + }, + }, +); + +/** + * Component definition for ComboboxListBox + * @public + */ +export const ComboboxListBoxDefinition = + defineComponent()({ + styles, + classNames: { + root: 'bui-ComboboxList', + noResults: 'bui-ComboboxNoResults', + }, + propDefs: { + options: {}, + }, + }); + +/** + * Component definition for ComboboxListBoxItem + * @public + */ +export const ComboboxListBoxItemDefinition = + defineComponent()({ + styles, + classNames: { + root: 'bui-ComboboxItem', + indicator: 'bui-ComboboxItemIndicator', + label: 'bui-ComboboxItemLabel', + }, + propDefs: {}, + }); + +/** + * Component definition for ComboboxSection + * @public + */ +export const ComboboxSectionDefinition = + defineComponent()({ + styles, + classNames: { + root: 'bui-ComboboxSection', + header: 'bui-ComboboxSectionHeader', + }, + propDefs: {}, + }); diff --git a/packages/ui/src/components/Combobox/index.ts b/packages/ui/src/components/Combobox/index.ts new file mode 100644 index 0000000000..9c9a52ff1a --- /dev/null +++ b/packages/ui/src/components/Combobox/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 './Combobox'; +export * from './types'; +export { + ComboboxDefinition, + ComboboxInputDefinition, + ComboboxListBoxDefinition, + ComboboxListBoxItemDefinition, + ComboboxSectionDefinition, +} from './definition'; diff --git a/packages/ui/src/components/Combobox/types.ts b/packages/ui/src/components/Combobox/types.ts new file mode 100644 index 0000000000..6d2c0423e7 --- /dev/null +++ b/packages/ui/src/components/Combobox/types.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ReactNode } from 'react'; +import type { ComboBoxProps as AriaComboBoxProps } from 'react-aria-components'; +import type { Breakpoint } from '../..'; +import type { FieldLabelProps } from '../FieldLabel/types'; +import type { Option, OptionSection } from '../Select/types'; + +export type { Option, OptionSection }; + +/** @public */ +export type ComboboxOwnProps = { + /** + * An icon to render before the input + */ + icon?: ReactNode; + + /** + * The size of the combobox field + * @defaultValue 'small' + */ + size?: 'small' | 'medium' | Partial>; + + /** + * The options of the combobox field. Pass flat options, option sections for + * grouped display, or a mix of both in the same array. + */ + options?: Array
); }; diff --git a/packages/ui/src/components/SearchField/SearchField.module.css b/packages/ui/src/components/SearchField/SearchField.module.css index b52c313a7d..6bfbb419f8 100644 --- a/packages/ui/src/components/SearchField/SearchField.module.css +++ b/packages/ui/src/components/SearchField/SearchField.module.css @@ -23,7 +23,6 @@ font-family: var(--bui-font-regular); width: 100%; flex: 1; - flex-shrink: 0; &[data-size='small'] { --search-field-item-height: 2rem; diff --git a/packages/ui/src/components/Select/Select.module.css b/packages/ui/src/components/Select/Select.module.css index c5ce30e363..c0d3d139fa 100644 --- a/packages/ui/src/components/Select/Select.module.css +++ b/packages/ui/src/components/Select/Select.module.css @@ -28,6 +28,13 @@ } } + .bui-Select { + display: flex; + flex-direction: column; + width: 100%; + flex: 1; + } + .bui-SelectPopover { min-width: var(--trigger-width); } @@ -251,6 +258,25 @@ } } + .bui-SelectSection { + &:first-child .bui-SelectSectionHeader { + padding-top: 0; + } + } + + .bui-SelectSectionHeader { + height: 2rem; + display: flex; + align-items: center; + padding-top: var(--bui-space-3); + padding-left: var(--bui-space-3); + color: var(--bui-fg-primary); + font-size: var(--bui-font-size-1); + font-weight: bold; + letter-spacing: 0.05rem; + text-transform: uppercase; + } + .bui-SelectNoResults { padding-inline: var(--bui-space-3); padding-block: var(--bui-space-2); diff --git a/packages/ui/src/components/Select/Select.stories.tsx b/packages/ui/src/components/Select/Select.stories.tsx index cf410e43a1..b4fc111eb9 100644 --- a/packages/ui/src/components/Select/Select.stories.tsx +++ b/packages/ui/src/components/Select/Select.stories.tsx @@ -105,6 +105,51 @@ export const SearchableMultiple = meta.story({ }, }); +const sectionedOptions = [ + { + title: 'Serif Fonts', + options: [ + { value: 'times', label: 'Times New Roman' }, + { value: 'georgia', label: 'Georgia' }, + { value: 'garamond', label: 'Garamond' }, + ], + }, + { + title: 'Sans-Serif Fonts', + options: [ + { value: 'arial', label: 'Arial' }, + { value: 'helvetica', label: 'Helvetica' }, + { value: 'verdana', label: 'Verdana' }, + ], + }, + { + title: 'Monospace Fonts', + options: [ + { value: 'courier', label: 'Courier New' }, + { value: 'consolas', label: 'Consolas' }, + { value: 'fira', label: 'Fira Code' }, + ], + }, +]; + +export const WithSections = meta.story({ + args: { + label: 'Font Family', + options: sectionedOptions, + name: 'font', + }, +}); + +export const SearchableWithSections = meta.story({ + args: { + label: 'Font Family', + searchable: true, + searchPlaceholder: 'Search fonts...', + options: sectionedOptions, + name: 'font', + }, +}); + export const Preview = meta.story({ args: { label: 'Font Family', diff --git a/packages/ui/src/components/Select/SelectContent.tsx b/packages/ui/src/components/Select/SelectContent.tsx index 2797e92d2d..e08fb92d85 100644 --- a/packages/ui/src/components/Select/SelectContent.tsx +++ b/packages/ui/src/components/Select/SelectContent.tsx @@ -25,12 +25,12 @@ import { RiCloseCircleLine } from '@remixicon/react'; import { useDefinition } from '../../hooks/useDefinition'; import { SelectContentDefinition } from './definition'; import { SelectListBox } from './SelectListBox'; -import type { Option } from './types'; +import type { SelectOwnProps } from './types'; interface SelectContentProps { searchable?: boolean; searchPlaceholder?: string; - options?: Array