diff --git a/.changeset/eight-planets-see.md b/.changeset/eight-planets-see.md
new file mode 100644
index 0000000000..20adcac7ef
--- /dev/null
+++ b/.changeset/eight-planets-see.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder': patch
+---
+
+render details for composite property schemas
diff --git a/.changeset/evil-cooks-watch.md b/.changeset/evil-cooks-watch.md
new file mode 100644
index 0000000000..0982f24634
--- /dev/null
+++ b/.changeset/evil-cooks-watch.md
@@ -0,0 +1,21 @@
+---
+'@backstage/plugin-catalog-unprocessed-entities': patch
+'@backstage/plugin-app-visualizer': patch
+'@backstage/plugin-catalog-import': patch
+'@backstage/plugin-catalog-graph': patch
+'@backstage/plugin-notifications': patch
+'@backstage/plugin-user-settings': patch
+'@backstage/plugin-kubernetes': patch
+'@backstage/plugin-scaffolder': patch
+'@backstage/plugin-api-docs': patch
+'@backstage/plugin-devtools': patch
+'@backstage/plugin-techdocs': patch
+'@backstage/plugin-catalog': patch
+'@backstage/plugin-signals': patch
+'@backstage/plugin-search': patch
+'@backstage/plugin-home': patch
+'@backstage/plugin-app': patch
+'@backstage/plugin-org': patch
+---
+
+Added the `info.packageJson` option to the plugin instance for the new frontend system.
diff --git a/.changeset/grumpy-dryers-act.md b/.changeset/grumpy-dryers-act.md
new file mode 100644
index 0000000000..caaeac5fa8
--- /dev/null
+++ b/.changeset/grumpy-dryers-act.md
@@ -0,0 +1,5 @@
+---
+'@backstage/repo-tools': patch
+---
+
+Add missing highlight language for the `package-docs` command.
diff --git a/.changeset/honest-moles-bet.md b/.changeset/honest-moles-bet.md
new file mode 100644
index 0000000000..22e0cb4533
--- /dev/null
+++ b/.changeset/honest-moles-bet.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch
+'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch
+'@backstage/plugin-scaffolder-node': patch
+---
+
+Update pull request creation filter to include .gitignore files in the created pull request
diff --git a/.changeset/petite-candies-tan.md b/.changeset/petite-candies-tan.md
new file mode 100644
index 0000000000..6ec5c9c813
--- /dev/null
+++ b/.changeset/petite-candies-tan.md
@@ -0,0 +1,29 @@
+---
+'@backstage/frontend-plugin-api': patch
+---
+
+Added a new optional `info` option to `createFrontendPlugin` that lets you provide a loaders for different sources of metadata information about the plugin.
+
+There are two available loaders. The first one is `info.packageJson`, which can be used to point to a `package.json` file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this:
+
+```ts
+export default createFrontendPlugin({
+ pluginId: '...',
+ info: {
+ packageJson: () => import('../package.json'),
+ },
+});
+```
+
+The second loader is `info.manifest`, which can be used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `spec.owner`.
+
+Typical usage looks like this:
+
+```ts
+export default createFrontendPlugin({
+ pluginId: '...',
+ info: {
+ manifest: () => import('../catalog-info.yaml'),
+ },
+});
+```
diff --git a/.changeset/puny-pillows-wave.md b/.changeset/puny-pillows-wave.md
new file mode 100644
index 0000000000..813e603007
--- /dev/null
+++ b/.changeset/puny-pillows-wave.md
@@ -0,0 +1,5 @@
+---
+'@backstage/frontend-plugin-api': patch
+---
+
+Added a new `useAppNode` hook, which can be used to get a reference to the `AppNode` from by the closest `ExtensionBoundary`.
diff --git a/.changeset/small-dots-march.md b/.changeset/small-dots-march.md
new file mode 100644
index 0000000000..0796ef68bb
--- /dev/null
+++ b/.changeset/small-dots-march.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-backend-module-gitlab': patch
+---
+
+Support merge request labels in publish:gitlab:merge-request
diff --git a/.changeset/smooth-eels-think.md b/.changeset/smooth-eels-think.md
new file mode 100644
index 0000000000..c5e2fe0c85
--- /dev/null
+++ b/.changeset/smooth-eels-think.md
@@ -0,0 +1,8 @@
+---
+'@backstage/plugin-techdocs': minor
+'@backstage/plugin-techdocs-react': minor
+'@backstage/plugin-catalog': minor
+'@backstage/plugin-techdocs-common': patch
+---
+
+Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`.
diff --git a/.changeset/spotty-cases-show.md b/.changeset/spotty-cases-show.md
new file mode 100644
index 0000000000..3e9a607733
--- /dev/null
+++ b/.changeset/spotty-cases-show.md
@@ -0,0 +1,5 @@
+---
+'@backstage/frontend-defaults': patch
+---
+
+Forwarded the new `pluginInfoResolver` option for `createApp`.
diff --git a/.changeset/stupid-flies-speak.md b/.changeset/stupid-flies-speak.md
new file mode 100644
index 0000000000..5156a5b8b6
--- /dev/null
+++ b/.changeset/stupid-flies-speak.md
@@ -0,0 +1,5 @@
+---
+'@backstage/frontend-app-api': patch
+---
+
+Implemented support for the `plugin.info()` method in specialized apps with a default resolved for `package.json` and `catalog-info.yaml`. The default resolution logic can be overridden via the `pluginInfoResolver` option to `createSpecializedApp`, and plugin-specific overrides can be applied via the new `app.pluginOverrides` key in static configuration.
diff --git a/.changeset/sweet-ducks-wait.md b/.changeset/sweet-ducks-wait.md
new file mode 100644
index 0000000000..4792fafe84
--- /dev/null
+++ b/.changeset/sweet-ducks-wait.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-test-utils': minor
+---
+
+Added mock implementations for `ActionsService` and `ActionsRegistryService`
diff --git a/.changeset/tough-heads-knock.md b/.changeset/tough-heads-knock.md
new file mode 100644
index 0000000000..da2e2c1163
--- /dev/null
+++ b/.changeset/tough-heads-knock.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend': patch
+---
+
+Update `refresh_state_references.id` to be a big int
diff --git a/.changeset/wet-bars-report.md b/.changeset/wet-bars-report.md
new file mode 100644
index 0000000000..d556f6cc61
--- /dev/null
+++ b/.changeset/wet-bars-report.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-plugin-api': minor
+---
+
+Added `coreServices.actionsRegistry` and `coreServices.actions` to allow registration of distributed actions from plugins, and the ability to invoke these actions
diff --git a/.changeset/wet-bars-reporting.md b/.changeset/wet-bars-reporting.md
new file mode 100644
index 0000000000..7dc66cb280
--- /dev/null
+++ b/.changeset/wet-bars-reporting.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-defaults': patch
+---
+
+Added some default implementations for the `ActionsService` and `ActionsRegistryService` that allow registration of actions for a particular plugin.
diff --git a/app-config.yaml b/app-config.yaml
index 89e417fad3..eaee401d09 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -64,83 +64,11 @@ backend:
# See README.md in the proxy-backend plugin for information on the configuration format
proxy:
endpoints:
- '/circleci/api':
- target: https://circleci.com/api/v1.1
- headers:
- Circle-Token: ${CIRCLECI_AUTH_TOKEN}
-
- '/jenkins/api':
- target: http://localhost:8080
- headers:
- Authorization: ${JENKINS_BASIC_AUTH_HEADER}
-
- '/travisci/api':
- target: https://api.travis-ci.com
- changeOrigin: true
- headers:
- Authorization: ${TRAVISCI_AUTH_TOKEN}
- travis-api-version: '3'
-
- '/newrelic/apm/api':
- target: https://api.newrelic.com/v2
- headers:
- X-Api-Key: ${NEW_RELIC_REST_API_KEY}
- allowedHeaders:
- - link
-
- '/newrelic/api':
- target: https://api.newrelic.com
- headers:
- X-Api-Key: ${NEW_RELIC_USER_KEY}
-
'/pagerduty':
target: https://api.pagerduty.com
headers:
Authorization: Token token=${PAGERDUTY_TOKEN}
- '/buildkite/api':
- target: https://api.buildkite.com/v2/
- headers:
- Authorization: ${BUILDKITE_TOKEN}
-
- '/sentry/api':
- target: https://sentry.io/api/
- allowedMethods: ['GET']
- headers:
- Authorization: ${SENTRY_TOKEN}
-
- '/ilert':
- target: https://api.ilert.com
- allowedMethods: ['GET', 'POST', 'PUT']
- allowedHeaders: ['Authorization']
- headers:
- Authorization: ${ILERT_AUTH_HEADER}
-
- '/airflow':
- target: https://your.airflow.instance.com/api/v1
- headers:
- Authorization: ${AIRFLOW_BASIC_AUTH_HEADER}
-
- '/gocd':
- target: https://your.gocd.instance.com/go/api
- allowedMethods: ['GET']
- allowedHeaders: ['Authorization']
- headers:
- Authorization: Basic ${GOCD_AUTH_CREDENTIALS}
-
- '/dynatrace':
- target: https://your.dynatrace.instance.com/api/v2
- headers:
- Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}'
-
- '/stackstorm':
- target: https://your.stackstorm.instance.com/api
- headers:
- St2-Api-Key: ${ST2_API_KEY}
-
- '/puppetdb':
- target: https://your.puppetdb.instance.com
-
organization:
name: My Company
@@ -157,46 +85,6 @@ techdocs:
publisher:
type: 'local' # Alternatives - 'googleGcs' or 'awsS3' or 'azureBlobStorage' or 'openStackSwift'. Read documentation for using alternatives.
-dynatrace:
- baseUrl: https://your.dynatrace.instance.com
-
-nomad:
- addr: 0.0.0.0
-
-# Score-cards sample configuration.
-scorecards:
- jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/
- wikiLinkTemplate: https://link-to-wiki/{id}
-
-sentry:
- organization: my-company
-
-rollbar:
- organization: my-company
- # NOTE: The rollbar-backend & accountToken key may be deprecated in the future (replaced by a proxy config)
- accountToken: my-rollbar-account-token
-
-lighthouse:
- baseUrl: http://localhost:3003
-
-kubernetes:
- serviceLocatorMethod:
- type: 'multiTenant'
- clusterLocatorMethods:
- - type: 'config'
- clusters: []
-
-kafka:
- clientId: backstage
- clusters:
- - name: cluster
- dashboardUrl: https://akhq.io/
- brokers:
- - localhost:9092
-
-allure:
- baseUrl: http://localhost:5050/allure-docker-service
-
integrations:
github:
- host: github.com
@@ -269,26 +157,6 @@ catalog:
plugins:
- catalog
- search
-
- processors:
- ldapOrg:
- ### Example for how to add your enterprise LDAP server
- # providers:
- # - target: ldaps://ds.example.net
- # bind:
- # dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net
- # secret: ${LDAP_SECRET}
- # users:
- # dn: ou=people,ou=example,dc=example,dc=net
- # options:
- # filter: (uid=*)
- # map:
- # description: l
- # groups:
- # dn: ou=access,ou=groups,ou=example,dc=example,dc=net
- # options:
- # filter: (&(objectClass=some-group-class)(!(groupType=email)))
-
locations:
# Add a location here to ingest it, for example from a URL:
#
@@ -325,13 +193,14 @@ catalog:
target: ../../plugins/scaffolder-backend/sample-templates/all-templates.yaml
rules:
- allow: [Template]
+
scaffolder:
# Use to customize default commit author info used when new components are created
- # defaultAuthor:
- # name: Scaffolder
- # email: scaffolder@backstage.io
+ defaultAuthor:
+ name: Scaffolder
+ email: scaffolder@backstage.io
# Use to customize the default commit message when new components are created
- # defaultCommitMessage: 'Initial commit'
+ defaultCommitMessage: 'Initial commit'
auth:
### Add auth.keyStore.provider to more granularly control how to store JWK data when running
@@ -422,80 +291,5 @@ auth:
myproxy: {}
guest: {}
-costInsights:
- engineerCost: 200000
- engineerThreshold: 0.5
- products:
- computeEngine:
- name: Compute Engine
- icon: compute
- cloudDataflow:
- name: Cloud Dataflow
- icon: data
- cloudStorage:
- name: Cloud Storage
- icon: storage
- bigQuery:
- name: BigQuery
- icon: search
- events:
- name: Events
- icon: data
- metrics:
- DAU:
- name: Daily Active Users
- default: true
- MSC:
- name: Monthly Subscribers
- currencies:
- engineers:
- label: 'Engineers 🛠'
- unit: 'engineer'
- usd:
- label: 'US Dollars 💵'
- kind: 'USD'
- unit: 'dollar'
- prefix: '$'
- rate: 1
- carbonOffsetTons:
- label: 'Carbon Offset Tons ♻️⚖️s'
- kind: 'CARBON_OFFSET_TONS'
- unit: 'carbon offset ton'
- rate: 3.5
- beers:
- label: 'Beers 🍺'
- kind: 'BEERS'
- unit: 'beer'
- rate: 4.5
- pintsIceCream:
- label: 'Pints of Ice Cream 🍦'
- kind: 'PINTS_OF_ICE_CREAM'
- unit: 'ice cream pint'
- rate: 5.5
-
-pagerDuty:
- eventsBaseUrl: 'https://events.pagerduty.com/v2'
-
-jenkins:
- instances:
- - name: default
- baseUrl: https://jenkins.example.com
- username: backstage-bot
- apiKey: 123456789abcdef0123456789abcedf012
-
-azureDevOps:
- host: dev.azure.com
- token: my-token
- organization: my-company
-
-apacheAirflow:
- baseUrl: https://your.airflow.instance.com
-
-gocd:
- baseUrl: https://your.gocd.instance.com
-
-stackstorm:
- webUrl: https://your.stackstorm.webui.instance.com
-
permission:
enabled: true
diff --git a/canon-docs/src/app/(docs)/releases/page.mdx b/canon-docs/src/app/(docs)/releases/page.mdx
index e71779e854..dcb96e5bf7 100644
--- a/canon-docs/src/app/(docs)/releases/page.mdx
+++ b/canon-docs/src/app/(docs)/releases/page.mdx
@@ -1,56 +1,77 @@
# Releases
+## Version 0.4.0
+
+### Main updates
+
+- ✨ Add new `Tab` component - [#29996](https://github.com/backstage/backstage/pull/29996)
+- ✨ Add `truncate` prop to `Text` and `Heading` - [#29988](https://github.com/backstage/backstage/pull/29988)
+- ✨ Add combobox option to `Menu` - [#29986](https://github.com/backstage/backstage/pull/29986)
+- ✨ Add icon prop on `TextField` - [#29820](https://github.com/backstage/backstage/pull/29820)
+- Improve icon props on `Button` and `IconButton` - [#29667](https://github.com/backstage/backstage/pull/29667)
+- Improve the way we treat custom render on `Text` and `Heading` - [#29989](https://github.com/backstage/backstage/pull/29989)
+- Improve `Menu` styles - [#29986](https://github.com/backstage/backstage/pull/29986)
+- Improve `TextField` styles - [#29974](https://github.com/backstage/backstage/pull/29974)
+- Improve clear button on `TextField` - [#29878](https://github.com/backstage/backstage/pull/29878)
+
+### Notable fixes
+
+- Fix spacing props on all layout components - [#30013](https://github.com/backstage/backstage/pull/30013)
+- Fix - Pin Base UI version - [#29782](https://github.com/backstage/backstage/pull/29782)
+- Fix - Clicking `Select` label moves focus to trigger - [#29755](https://github.com/backstage/backstage/pull/29755)
+- Fix `DataTable.Pagination` count issue - [#29688](https://github.com/backstage/backstage/pull/29688)
+
## Version 0.3.0
### Main updates
-- Add `DataTable` component - ([#29484](https://github.com/backstage/backstage/pull/29484), [#29603](https://github.com/backstage/backstage/pull/29603))
-- Add `Select` component - ([#29440](https://github.com/backstage/backstage/pull/29440))
-- Add `Avatar` component - ([#29594](https://github.com/backstage/backstage/pull/29594))
-- Add `Collapsible` component - ([#29617](https://github.com/backstage/backstage/pull/29617))
-- Add `TextField` component instead of `Field` + `Input` - ([#29364](https://github.com/backstage/backstage/pull/29364))
-- Add `TableCellProfile` - ([#29600](https://github.com/backstage/backstage/pull/29600))
-- Add breakpoint hooks - `up()` and `down()` - ([#29564](https://github.com/backstage/backstage/pull/29564))
-- Add gray scale css tokens - ([#29543](https://github.com/backstage/backstage/pull/29543))
-- Update CSS styling API using `[data-___]` instead of class names for props - ([#29560](https://github.com/backstage/backstage/pull/29560))
-- Update `Checkbox` dark mode - ([#29544](https://github.com/backstage/backstage/pull/29544))
-- Update `Container` styles - ([#29475](https://github.com/backstage/backstage/pull/29475))
-- Update `Menu` styles - ([#29351](https://github.com/backstage/backstage/pull/29351))
-- Fix `Select` styles on small sizes + with long option names - ([#29545](https://github.com/backstage/backstage/pull/29545))
-- Fix render prop on `Link` - ([#29247](https://github.com/backstage/backstage/pull/29247))
-- Remove `Field` from `TextField` + `Select` - ([#29482](https://github.com/backstage/backstage/pull/29482))
-- Update `textDecoration` to `none` on `Text` / `Heading` - ([#29357](https://github.com/backstage/backstage/pull/29357))
+- Add `DataTable` component - [#29484](https://github.com/backstage/backstage/pull/29484), [#29603](https://github.com/backstage/backstage/pull/29603)
+- Add `Select` component - [#29440](https://github.com/backstage/backstage/pull/29440)
+- Add `Avatar` component - [#29594](https://github.com/backstage/backstage/pull/29594)
+- Add `Collapsible` component - [#29617](https://github.com/backstage/backstage/pull/29617)
+- Add `TextField` component instead of `Field` + `Input` - [#29364](https://github.com/backstage/backstage/pull/29364)
+- Add `TableCellProfile` - [#29600](https://github.com/backstage/backstage/pull/29600)
+- Add breakpoint hooks - `up()` and `down()` - [#29564](https://github.com/backstage/backstage/pull/29564)
+- Add gray scale css tokens - [#29543](https://github.com/backstage/backstage/pull/29543)
+- Update CSS styling API using `[data-___]` instead of class names for props - [#29560](https://github.com/backstage/backstage/pull/29560)
+- Update `Checkbox` dark mode - [#29544](https://github.com/backstage/backstage/pull/29544)
+- Update `Container` styles - [#29475](https://github.com/backstage/backstage/pull/29475)
+- Update `Menu` styles - [#29351](https://github.com/backstage/backstage/pull/29351)
+- Fix `Select` styles on small sizes + with long option names - [#29545](https://github.com/backstage/backstage/pull/29545)
+- Fix render prop on `Link` - [#29247](https://github.com/backstage/backstage/pull/29247)
+- Remove `Field` from `TextField` + `Select` - [#29482](https://github.com/backstage/backstage/pull/29482)
+- Update `textDecoration` to `none` on `Text` / `Heading` - [#29357](https://github.com/backstage/backstage/pull/29357)
### Notable fixes
-- Docs - Use stories from Storybook for all examples in Nextjs - ([#29306](https://github.com/backstage/backstage/pull/29306))
-- Docs - Add release page (this one 🤗) - ([#29461](https://github.com/backstage/backstage/pull/29461))
-- Docs - Add docs for Menu, Link - ([#29576](https://github.com/backstage/backstage/pull/29576))
-- Fix CSS watch mode - ([#29352](https://github.com/backstage/backstage/pull/29352))
+- Docs - Use stories from Storybook for all examples in Nextjs - [#29306](https://github.com/backstage/backstage/pull/29306)
+- Docs - Add release page (this one 🤗) - [#29461](https://github.com/backstage/backstage/pull/29461)
+- Docs - Add docs for Menu, Link - [#29576](https://github.com/backstage/backstage/pull/29576)
+- Fix CSS watch mode - [#29352](https://github.com/backstage/backstage/pull/29352)
## Version 0.2.0
### Main updates
-- New `Tooltip` component ([#29241](https://github.com/backstage/backstage/pull/29241))
-- New `Menu` component. ([#29151](https://github.com/backstage/backstage/pull/29151))
-- New `IconButton` component. ([#29239](https://github.com/backstage/backstage/pull/29239))
-- New `ScrollArea` component. ([#29240](https://github.com/backstage/backstage/pull/29240))
-- Improve `Button` & `Checkbox` styles. ([#29127](https://github.com/backstage/backstage/pull/29127)) ([#28789](https://github.com/backstage/backstage/pull/28789))
-- Improve `Text` styles. ([#29200](https://github.com/backstage/backstage/pull/29200))
-- Renamed `CanonProvider` to `IconProvider`. ([#29002](https://github.com/backstage/backstage/pull/29002))
-- Added about 40+ new icons. ([#29264](https://github.com/backstage/backstage/pull/29264))
-- Simplified styling into a unique styles.css file ([#29199](https://github.com/backstage/backstage/pull/29199))
-- Added Canon styles to Backstage ([#29137](https://github.com/backstage/backstage/pull/29137))
-- Update global CSS tokens ([#28804](https://github.com/backstage/backstage/pull/28804))
-- Merge Stack + Inline into Flex ([#28634](https://github.com/backstage/backstage/pull/28634))
+- New `Tooltip` component - [#29241](https://github.com/backstage/backstage/pull/29241)
+- New `Menu` component - [#29151](https://github.com/backstage/backstage/pull/29151)
+- New `IconButton` component - [#29239](https://github.com/backstage/backstage/pull/29239)
+- New `ScrollArea` component - [#29240](https://github.com/backstage/backstage/pull/29240)
+- Improve `Button` & `Checkbox` styles - [#29127](https://github.com/backstage/backstage/pull/29127), [#28789](https://github.com/backstage/backstage/pull/28789)
+- Improve `Text` styles - [#29200](https://github.com/backstage/backstage/pull/29200)
+- Renamed `CanonProvider` to `IconProvider` - [#29002](https://github.com/backstage/backstage/pull/29002)
+- Added about 40+ new icons - [#29264](https://github.com/backstage/backstage/pull/29264)
+- Simplified styling into a unique styles.css file - [#29199](https://github.com/backstage/backstage/pull/29199)
+- Added Canon styles to Backstage - [#29137](https://github.com/backstage/backstage/pull/29137)
+- Update global CSS tokens - [#28804](https://github.com/backstage/backstage/pull/28804)
+- Merge Stack + Inline into Flex - [#28634](https://github.com/backstage/backstage/pull/28634)
### Notable fixes:
-- Improve `Button` types. ([#29205](https://github.com/backstage/backstage/pull/29205))
-- Move font weight and family back to each components ([#28972](https://github.com/backstage/backstage/pull/28972))
-- Fix custom values in spacing props ([#28770](https://github.com/backstage/backstage/pull/28770))
-- Multiple updates on the Canon Docs site ([#28760](https://github.com/backstage/backstage/pull/28760)) ([#28591](https://github.com/backstage/backstage/pull/28591))
+- Improve `Button` types - [#29205](https://github.com/backstage/backstage/pull/29205)
+- Move font weight and family back to each components - [#28972](https://github.com/backstage/backstage/pull/28972)
+- Fix custom values in spacing props - [#28770](https://github.com/backstage/backstage/pull/28770)
+- Multiple updates on the Canon Docs site - [#28760](https://github.com/backstage/backstage/pull/28760), [#28591](https://github.com/backstage/backstage/pull/28591)
## Version 0.1.0
diff --git a/canon-docs/src/app/(playground)/playground/page.tsx b/canon-docs/src/app/(playground)/playground/page.tsx
index 3f1675551e..671d644993 100644
--- a/canon-docs/src/app/(playground)/playground/page.tsx
+++ b/canon-docs/src/app/(playground)/playground/page.tsx
@@ -80,11 +80,11 @@ const Content = () => {
const Line = ({ content, title }: { content: ReactNode; title: string }) => {
return (
-
+ {title}{content}
-
+
);
};
diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md
index 974fa80993..42cefd3adb 100644
--- a/docs/features/software-catalog/well-known-annotations.md
+++ b/docs/features/software-catalog/well-known-annotations.md
@@ -115,6 +115,20 @@ the TechDocs in the TechDocs page or needing multiple builds of the same docs.
This is for situations where you have complex systems where they share a single repo, and likely a single TechDoc location.
+### backstage.io/techdocs-entity-path
+
+```yaml
+# Example:
+metadata:
+ annotations:
+ backstage.io/techdocs-entity: component:default/example
+ backstage.io/techdocs-entity-path: /path/to/this/component
+```
+
+The value of this annotation informs of the path to this component's TechDocs within an external entity that owns the TechDocs.
+In conjunction with [backstage.io/techdocs-entity](#backstageiotechdocs-entity) this allows for deep linking into the TechDocs of
+another entity, not just linking to the root of another entities TechDocs.
+
### backstage.io/view-url, backstage.io/edit-url
```yaml
diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md
index 8a95c86533..7d8c99ffda 100644
--- a/docs/features/techdocs/how-to-guides.md
+++ b/docs/features/techdocs/how-to-guides.md
@@ -942,6 +942,35 @@ metadata:
backstage.io/techdocs-entity: system:default/example
```
+### Deep linking into TechDocs
+
+The `backstage.io/techdocs-entity-path` annotation can be use to deep link into a specific page within the components TechDocs.
+This can be used in conjunction with `backstage.io/techdocs-entity` or standalone.
+
+```yaml
+apiVersion: backstage.io/v1alpha1
+kind: System
+metadata:
+ name: example
+ namespace: default
+ title: Example
+ description: This is the parent entity
+ annotations:
+ backstage.io/techdocs-ref: dir:.
+
+---
+apiVersion: backstage.io/v1alpha1
+kind: Component
+metadata:
+ name: example-platfrom
+ title: Example Application Platform
+ namespace: default
+ description: This is the child entity
+ annotations:
+ backstage.io/techdocs-entity: system:default/example
+ backstage.io/techdocs-entity-path: /path/to/component/docs
+```
+
## How to resolve broken links from moved or renamed pages in your documentation site
TechDocs supports using the [mkdocs-redirects](https://github.com/mkdocs/mkdocs-redirects/tree/master) plugin to create a redirect map for any TechDocs site. This allows broken links from renamed or moved pages in your site to be redirected to their specified replacement.
diff --git a/docs/frontend-system/architecture/10-app.md b/docs/frontend-system/architecture/10-app.md
index 0fa4ba04cc..f0d7ff3d1e 100644
--- a/docs/frontend-system/architecture/10-app.md
+++ b/docs/frontend-system/architecture/10-app.md
@@ -77,3 +77,98 @@ app:
```
Note that you do not need to manually exclude packages that you also import explicitly in code, since plugin instances are deduplicated by the app. You will never end up with duplicate plugin installations except if they are in fact two different plugin instances with different IDs.
+
+## Plugin Info Resolution
+
+When a plugin is installed in an app it may provide sources of information about the plugin that can be useful to end users and admins. This includes things like what version of a plugin is running, what team owns the plugin, and who to contact for support. You can read more about how the plugins provide this information in the [plugins `info` option section](./15-plugins.md#info).
+
+By default the app will pick a few common fields from `package.json` files, and assume that the opaque manifests are `catalog-info.yaml` files that some information can be gathered from too. This information will then be available via the `info()` method on plugin instances, returning a structure of the `FrontendPluginInfo` type.
+
+### Extending Plugin Info
+
+The default plugin info is intended as a base to build upon. As part of setting up an app you can both customize the way that the plugin info is resolved, as well as extend the `FrontendPluginInfo` type to include more information.
+
+In order to extend the `FrontendPluginInfo` type you use [TypeScript module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation). This makes it possible to extend the `FrontendPluginInfo` interface with additional fields, which you can then add custom resolution logic for as well as access within the app. For example, you might add a `slackChannel` field as follows:
+
+```ts
+declare module '@backstage/frontend-plugin-api' {
+ interface FrontendPluginInfo {
+ /**
+ * The slack channel to use for support requests for this plugin.
+ */
+ slackChannel?: string;
+ }
+}
+```
+
+### Customizing Plugin Info Resolution
+
+With the new `slackChannel` field in place, we now need to provide a custom resolver that knows how to extract this information from the plugin information sources. This is done by passing a custom `pluginInfoResolver` to `createApp`, which in our example is declared like this:
+
+```ts title="pluginInfoResolver.ts"
+import { createPluginInfoResolver } from '@backstage/frontend-plugin-api';
+
+// It is recommended to keep the above module augmentation in this file too
+
+export const pluginInfoResolver: FrontendPluginInfoResolver = async ctx => {
+ // In our particular example app we assume that all plugin manifests are catalog-info.yaml files
+ const manifest = (await ctx.manifest?.()) as Entity | undefined;
+
+ // Call the default resolver to populate common fields
+ const { info } = await ctx.defaultResolver({
+ packageJson: await ctx.packageJson(),
+ manifest: manifest,
+ });
+
+ // In this example the catalog model has been extended with a metadata.slackChannel field
+ const slackChannel = manifest?.metadata?.slackChannel?.toString();
+
+ if (slackChannel) {
+ info.slackChannel = slackChannel;
+ info.links = [
+ ...(info.links ?? []),
+ {
+ title: 'Slack Channel',
+ url: `https://our-workspace.enterprise.slack.com/archives/${slackChannel}`,
+ },
+ ];
+ }
+
+ return { info };
+};
+```
+
+And included in the app as follows:
+
+```ts title="App.tsx"
+import { pluginInfoResolver } from './pluginInfoResolver';
+
+const app = createApp({
+ pluginInfoResolver,
+ // ... other options
+});
+```
+
+### Overriding Plugin Info
+
+Another way to customize the plugin info is to use the `app.pluginOverrides` static configuration key. These overrides are applied after the plugin info has been resolved as a final step before making it available to users. These overrides are particularly useful to override information in third-party plugins. For example, if your organization has an individual team that is responsible for the maintenance of the Software Catalog, you might configure the following override:
+
+```yaml
+app:
+ pluginOverrides:
+ - match:
+ pluginId: catalog
+ info:
+ ownerEntityRefs: [catalog-owners]
+```
+
+You can match on both the `pluginId` and/or `packageName` of the plugin, although the `packageName` will only be supported if the plugin provides an loader for the `package.json` file. Using `//` you are also able to use a regex pattern for this matching. For example, if you wanted to override the owner for all plugins from the `@acme` namespace, you could do the following:
+
+```yaml
+app:
+ pluginOverrides:
+ - match:
+ packageName: /@acme/.*/
+ info:
+ ownerEntityRefs: [acme-owners]
+```
diff --git a/docs/frontend-system/architecture/15-plugins.md b/docs/frontend-system/architecture/15-plugins.md
index 825f2a3982..6d2b14d77f 100644
--- a/docs/frontend-system/architecture/15-plugins.md
+++ b/docs/frontend-system/architecture/15-plugins.md
@@ -53,6 +53,35 @@ These are the routes that the plugin exposes to the app. The `routes` option dec
This is a list of feature flag declarations that your plugin provides to the app. This makes sure that the feature flags are correctly registered and can be toggled in the app. To read a feature flag you can use the feature flags [Utility API](../architecture/33-utility-apis.md), accessible via `featureFlagsApiRef`.
+### `info` option
+
+This options is used to provide loaders for different sources of information about the plugin that may be useful to users and admins. The two available loaders are `packageJson` and `manifest`, and a plugin can use either or both as needed. The resulting information is available via the `info()` method on the plugin instance once it is installed in an app, but it is up to each app to decide how to derive the information from the provided sources.
+
+The `info.packageJson` loader **MUST** be used by all plugins that are implemented within their own package, and it should load the `package.json` file for the plugin package. Typical usage looks like this:
+
+```ts
+export default createFrontendPlugin({
+ pluginId: 'my-plugin',
+ info: {
+ packageJson: () => import('../package.json'),
+ },
+ extensions: [...],
+});
+```
+
+The `info.manifest` loader is used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `metadata.links` and `spec.owner`.
+
+Typical usage looks like this:
+
+```ts
+export default createFrontendPlugin({
+ pluginId: '...',
+ info: {
+ manifest: () => import('../catalog-info.yaml'),
+ },
+});
+```
+
## Installing a Plugin in an App
A plugin instance is considered a frontend feature and can be installed directly in any Backstage frontend app. See the [app documentation](./10-app.md) for more information about the different ways in which you can install new features in an app.
diff --git a/microsite/data/plugins/wheel-of-names.yaml b/microsite/data/plugins/wheel-of-names.yaml
new file mode 100644
index 0000000000..0377742ab0
--- /dev/null
+++ b/microsite/data/plugins/wheel-of-names.yaml
@@ -0,0 +1,10 @@
+---
+title: Wheel of Names
+author: intive
+authorUrl: https://www.intive.com/
+category: Utility
+description: This plugin provides a customizable spinning wheel that can be used for random selection, decision making, or just for fun in your Backstage instance.
+documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/wheel-of-names/plugins/wheel-of-names/README.md
+iconUrl: /img/wheel-of-names.svg
+npmPackageName: '@backstage-community/plugin-wheel-of-names'
+addedDate: '2025-05-21'
diff --git a/microsite/static/img/wheel-of-names.svg b/microsite/static/img/wheel-of-names.svg
new file mode 100644
index 0000000000..d6f19a06fb
--- /dev/null
+++ b/microsite/static/img/wheel-of-names.svg
@@ -0,0 +1,4 @@
+
diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml
index 0e6dd0a356..da233b0188 100644
--- a/packages/app-next/app-config.yaml
+++ b/packages/app-next/app-config.yaml
@@ -8,6 +8,20 @@ app:
catalog.createComponent: catalog-import.importPage
org.catalogIndex: catalog.catalogIndex
+ pluginOverrides:
+ - match:
+ pluginId: pages
+ info:
+ description: 'This description was overridden in packages/app-next/app-config.yaml'
+ - match:
+ pluginId: /^catalog(-.*)?$/
+ info:
+ ownerEntityRefs: [cubic-belugas]
+ - match:
+ packageName: '@backstage/plugin-scaffolder'
+ info:
+ ownerEntityRefs: [cubic-belugas]
+
extensions:
# - apis.plugin.graphiql.browse.gitlab: true
# - graphiql-endpoint:graphiql/gitlab: true
diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx
index 0ecb46e06a..43cc63d1a4 100644
--- a/packages/app-next/src/App.tsx
+++ b/packages/app-next/src/App.tsx
@@ -43,6 +43,7 @@ import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha';
import { convertLegacyPlugin } from '@backstage/core-compat-api';
import { convertLegacyPageExtension } from '@backstage/core-compat-api';
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
+import { pluginInfoResolver } from './pluginInfoResolver';
/*
@@ -132,6 +133,7 @@ const app = createApp({
customHomePageModule,
...collectedLegacyPlugins,
],
+ pluginInfoResolver,
/* Handled through config instead */
// bindRoutes({ bind }) {
// bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX });
diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx
index ddd080c28b..33fc7d8c0b 100644
--- a/packages/app-next/src/examples/pagesPlugin.tsx
+++ b/packages/app-next/src/examples/pagesPlugin.tsx
@@ -21,7 +21,10 @@ import {
createExternalRouteRef,
useRouteRef,
PageBlueprint,
+ FrontendPluginInfo,
+ useAppNode,
} from '@backstage/frontend-plugin-api';
+import { useEffect, useState } from 'react';
import { Route, Routes } from 'react-router-dom';
const indexRouteRef = createRouteRef();
@@ -36,6 +39,22 @@ export const pageXRouteRef = createRouteRef();
// path: '/page2',
// });
+function PluginInfo() {
+ const node = useAppNode();
+ const [info, setInfo] = useState(undefined);
+
+ useEffect(() => {
+ node?.spec.source?.info().then(setInfo);
+ }, [node]);
+
+ return (
+