Merge branch 'master' into fix-auditor-length

Signed-off-by: John <john.r.k.redwood@gmail.com>
This commit is contained in:
John
2025-07-17 09:39:14 +10:00
committed by GitHub
1088 changed files with 42474 additions and 26204 deletions
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Fixed an issue causing TechDocs to not properly handle initial redirect.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-graph': patch
---
Catalog graph plugin support i18n
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
We are consolidating all css files into a single styles.css in Canon.
-14
View File
@@ -1,14 +0,0 @@
---
'@backstage/plugin-catalog-backend': major
'@backstage/create-app': patch
---
**BREAKING:** The experimental `catalog.useUrlReadersSearch` configuration flag (introduced in v1.36) has been removed.
The `UrlReaderProcessor` now always uses the `search` method of `UrlReaders`. Built-in `UrlReaderService` implementations have been updated accordingly.
If you use custom `UrlReaderService` implementations, you need to adapt their `search` method to correctly handle both specific URLs and potential
search patterns (see changes on built-in readers [in the original PR](https://github.com/backstage/backstage/pull/28379/files#diff-68b0452f173ee54bdd40f7b5e047a9cb8bb59200425622c212c217b76dac1d1b)).
Previous behavior was to call the `search` method only if the parsed Git URL's filename contained a wildcard and use `readUrl` otherwise. Each `UrlReaderService` must implement this logic in the `search` method instead.
This allows each `UrlReaderService` implementation to check whether it's a search URL (that contains a wildcard pattern) or not using logic that is specific to each provider.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
Add new SearchField component in Canon
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/config-loader': patch
'@backstage/config': patch
---
Loosen the requirements for a key to be considered valid config.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder': patch
---
Filter MultiEntityPicker options based on rendered option value
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
Add new `RadioGroup` + `Radio` component to Canon
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
---
Fixed bug in `IncrementalIngestionEngine` by adding `burstLength` check when a burst completes
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/backend-defaults': patch
'@backstage/backend-test-utils': minor
---
Add a standard `toString` on credentials objects
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Adding `type` as an override to the `convertLegacyEntityCardExtension`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-azure': patch
---
`host` should be optional in `config` schema
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/repo-tools': minor
---
Clear output directory before running `package-docs` and skip all internal packages.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-dynamic-feature-service': patch
---
Fix wrong imports which lead to module initialization failures when enabling dynamic plugins.
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/plugin-scaffolder-node-test-utils': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-node': patch
---
An internal refactor which adds additional types to experimental checkpoints
-233
View File
@@ -1,233 +0,0 @@
{
"mode": "pre",
"tag": "next",
"initialVersions": {
"example-app": "0.2.110",
"@backstage/app-defaults": "1.6.3",
"example-app-next": "0.0.24",
"app-next-example-plugin": "0.0.24",
"example-backend": "0.0.39",
"@backstage/backend-app-api": "1.2.4",
"@backstage/backend-defaults": "0.11.0",
"@backstage/backend-dev-utils": "0.1.5",
"@backstage/backend-dynamic-feature-service": "0.7.1",
"@backstage/backend-openapi-utils": "0.5.4",
"@backstage/backend-plugin-api": "1.4.0",
"@backstage/backend-test-utils": "1.6.0",
"@backstage/canon": "0.5.0",
"@backstage/catalog-client": "1.10.1",
"@backstage/catalog-model": "1.7.4",
"@backstage/cli": "0.33.0",
"@backstage/cli-common": "0.1.15",
"@backstage/cli-node": "0.2.13",
"@backstage/codemods": "0.1.52",
"@backstage/config": "1.3.2",
"@backstage/config-loader": "1.10.1",
"@backstage/core-app-api": "1.17.1",
"@backstage/core-compat-api": "0.4.3",
"@backstage/core-components": "0.17.3",
"@backstage/core-plugin-api": "1.10.8",
"@backstage/create-app": "0.7.0",
"@backstage/dev-utils": "1.1.11",
"e2e-test": "0.2.29",
"@backstage/e2e-test-utils": "0.1.1",
"@backstage/errors": "1.2.7",
"@backstage/eslint-plugin": "0.1.11",
"@backstage/frontend-app-api": "0.11.3",
"@backstage/frontend-defaults": "0.2.3",
"@backstage/frontend-dynamic-feature-loader": "0.1.2",
"@internal/frontend": "0.0.10",
"@backstage/frontend-plugin-api": "0.10.3",
"@backstage/frontend-test-utils": "0.3.3",
"@backstage/integration": "1.17.0",
"@backstage/integration-aws-node": "0.1.16",
"@backstage/integration-react": "1.2.8",
"@internal/opaque": "0.0.1",
"@backstage/release-manifests": "0.0.13",
"@backstage/repo-tools": "0.14.0",
"@internal/scaffolder": "0.0.10",
"@techdocs/cli": "1.9.4",
"techdocs-cli-embedded-app": "0.2.109",
"@backstage/test-utils": "1.7.9",
"@backstage/theme": "0.6.6",
"@backstage/types": "1.2.1",
"@backstage/version-bridge": "1.0.11",
"yarn-plugin-backstage": "0.0.6",
"@backstage/plugin-api-docs": "0.12.8",
"@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.10",
"@backstage/plugin-app": "0.1.10",
"@backstage/plugin-app-backend": "0.5.3",
"@backstage/plugin-app-node": "0.1.34",
"@backstage/plugin-app-visualizer": "0.1.20",
"@backstage/plugin-auth-backend": "0.25.1",
"@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-auth0-provider": "0.2.4",
"@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.9",
"@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.4",
"@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-github-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-google-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-guest-provider": "0.2.9",
"@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.9",
"@backstage/plugin-auth-backend-module-oidc-provider": "0.4.4",
"@backstage/plugin-auth-backend-module-okta-provider": "0.2.4",
"@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.4",
"@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.4",
"@backstage/plugin-auth-node": "0.6.4",
"@backstage/plugin-auth-react": "0.1.16",
"@backstage/plugin-bitbucket-cloud-common": "0.3.0",
"@backstage/plugin-catalog": "1.31.0",
"@backstage/plugin-catalog-backend": "2.1.0",
"@backstage/plugin-catalog-backend-module-aws": "0.4.12",
"@backstage/plugin-catalog-backend-module-azure": "0.3.6",
"@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.3",
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.0",
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.0",
"@backstage/plugin-catalog-backend-module-gcp": "0.3.9",
"@backstage/plugin-catalog-backend-module-gerrit": "0.3.3",
"@backstage/plugin-catalog-backend-module-gitea": "0.1.1",
"@backstage/plugin-catalog-backend-module-github": "0.10.0",
"@backstage/plugin-catalog-backend-module-github-org": "0.3.11",
"@backstage/plugin-catalog-backend-module-gitlab": "0.7.0",
"@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.10",
"@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.1",
"@backstage/plugin-catalog-backend-module-ldap": "0.11.6",
"@backstage/plugin-catalog-backend-module-logs": "0.1.11",
"@backstage/plugin-catalog-backend-module-msgraph": "0.7.1",
"@backstage/plugin-catalog-backend-module-openapi": "0.2.11",
"@backstage/plugin-catalog-backend-module-puppetdb": "0.2.11",
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.9",
"@backstage/plugin-catalog-backend-module-unprocessed": "0.6.1",
"@backstage/plugin-catalog-common": "1.1.4",
"@backstage/plugin-catalog-graph": "0.4.20",
"@backstage/plugin-catalog-import": "0.13.1",
"@backstage/plugin-catalog-node": "1.17.1",
"@backstage/plugin-catalog-react": "1.19.0",
"@backstage/plugin-catalog-unprocessed-entities": "0.2.18",
"@backstage/plugin-catalog-unprocessed-entities-common": "0.0.8",
"@backstage/plugin-config-schema": "0.1.69",
"@backstage/plugin-devtools": "0.1.28",
"@backstage/plugin-devtools-backend": "0.5.6",
"@backstage/plugin-devtools-common": "0.1.16",
"@backstage/plugin-events-backend": "0.5.3",
"@backstage/plugin-events-backend-module-aws-sqs": "0.4.12",
"@backstage/plugin-events-backend-module-azure": "0.2.21",
"@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.21",
"@backstage/plugin-events-backend-module-bitbucket-server": "0.1.2",
"@backstage/plugin-events-backend-module-gerrit": "0.2.21",
"@backstage/plugin-events-backend-module-github": "0.4.1",
"@backstage/plugin-events-backend-module-gitlab": "0.3.2",
"@backstage/plugin-events-backend-module-google-pubsub": "0.1.1",
"@backstage/plugin-events-backend-module-kafka": "0.1.0",
"@backstage/plugin-events-backend-test-utils": "0.1.45",
"@backstage/plugin-events-node": "0.4.12",
"@internal/plugin-todo-list": "1.0.40",
"@internal/plugin-todo-list-backend": "1.0.40",
"@internal/plugin-todo-list-common": "1.0.25",
"@backstage/plugin-gateway-backend": "1.0.2",
"@backstage/plugin-home": "0.8.9",
"@backstage/plugin-home-react": "0.1.27",
"@backstage/plugin-kubernetes": "0.12.8",
"@backstage/plugin-kubernetes-backend": "0.19.7",
"@backstage/plugin-kubernetes-cluster": "0.0.26",
"@backstage/plugin-kubernetes-common": "0.9.5",
"@backstage/plugin-kubernetes-node": "0.3.1",
"@backstage/plugin-kubernetes-react": "0.5.8",
"@backstage/plugin-mcp-actions-backend": "0.1.0",
"@backstage/plugin-notifications": "0.5.6",
"@backstage/plugin-notifications-backend": "0.5.7",
"@backstage/plugin-notifications-backend-module-email": "0.3.10",
"@backstage/plugin-notifications-backend-module-slack": "0.1.2",
"@backstage/plugin-notifications-common": "0.0.9",
"@backstage/plugin-notifications-node": "0.2.16",
"@backstage/plugin-org": "0.6.40",
"@backstage/plugin-org-react": "0.1.39",
"@backstage/plugin-permission-backend": "0.7.1",
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.9",
"@backstage/plugin-permission-common": "0.9.0",
"@backstage/plugin-permission-node": "0.10.1",
"@backstage/plugin-permission-react": "0.4.35",
"@backstage/plugin-proxy-backend": "0.6.3",
"@backstage/plugin-proxy-node": "0.1.5",
"@backstage/plugin-scaffolder": "1.32.0",
"@backstage/plugin-scaffolder-backend": "2.0.0",
"@backstage/plugin-scaffolder-backend-module-azure": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.11",
"@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.10",
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.11",
"@backstage/plugin-scaffolder-backend-module-gcp": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-gitea": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-github": "0.8.0",
"@backstage/plugin-scaffolder-backend-module-gitlab": "0.9.2",
"@backstage/plugin-scaffolder-backend-module-notifications": "0.1.11",
"@backstage/plugin-scaffolder-backend-module-rails": "0.5.10",
"@backstage/plugin-scaffolder-backend-module-sentry": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.11",
"@backstage/plugin-scaffolder-common": "1.5.11",
"@backstage/plugin-scaffolder-node": "0.9.0",
"@backstage/plugin-scaffolder-node-test-utils": "0.3.0",
"@backstage/plugin-scaffolder-react": "1.17.0",
"@backstage/plugin-search": "1.4.27",
"@backstage/plugin-search-backend": "2.0.3",
"@backstage/plugin-search-backend-module-catalog": "0.3.5",
"@backstage/plugin-search-backend-module-elasticsearch": "1.7.3",
"@backstage/plugin-search-backend-module-explore": "0.3.3",
"@backstage/plugin-search-backend-module-pg": "0.5.45",
"@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.10",
"@backstage/plugin-search-backend-module-techdocs": "0.4.3",
"@backstage/plugin-search-backend-node": "1.3.12",
"@backstage/plugin-search-common": "1.2.18",
"@backstage/plugin-search-react": "1.9.1",
"@backstage/plugin-signals": "0.0.20",
"@backstage/plugin-signals-backend": "0.3.5",
"@backstage/plugin-signals-node": "0.1.21",
"@backstage/plugin-signals-react": "0.0.14",
"@backstage/plugin-techdocs": "1.13.0",
"@backstage/plugin-techdocs-addons-test-utils": "1.0.49",
"@backstage/plugin-techdocs-backend": "2.0.3",
"@backstage/plugin-techdocs-common": "0.1.1",
"@backstage/plugin-techdocs-module-addons-contrib": "1.1.25",
"@backstage/plugin-techdocs-node": "1.13.4",
"@backstage/plugin-techdocs-react": "1.3.0",
"@backstage/plugin-user-settings": "0.8.23",
"@backstage/plugin-user-settings-backend": "0.3.3",
"@backstage/plugin-user-settings-common": "0.0.1"
},
"changesets": [
"chubby-dots-kiss",
"clear-bananas-end",
"curly-zoos-thank",
"cyan-islands-swim",
"dark-cougars-go",
"empty-mugs-agree",
"empty-poets-give",
"gentle-llamas-press",
"mean-lemons-dream",
"petite-paths-remain",
"public-nails-melt",
"red-trams-join",
"rich-eagles-rule",
"shaggy-cobras-rhyme",
"sharp-stars-report",
"silent-vans-tie",
"six-dots-agree",
"sixty-ties-matter",
"social-insects-cheat",
"stupid-donuts-sit",
"three-shoes-behave",
"tired-bats-attend",
"wicked-socks-share",
"wise-frogs-talk",
"yummy-pugs-battle"
]
}
-13
View File
@@ -1,13 +0,0 @@
---
'@backstage/canon': minor
---
**BREAKING CHANGES**
Were updating our Button component to provide better support for button links.
- Were introducing a new `ButtonLink` component, which replaces the previous render prop pattern.
- To maintain naming consistency across components, `IconButton` is being renamed to `ButtonIcon`.
- Additionally, the render prop will be removed from all button-related components.
These changes aim to simplify usage and improve clarity in our component API.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-notifications-backend': patch
---
Fix `addTopic` migration when `user_settings` present
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-mcp-actions-backend': patch
---
Fixed the example in the README for generating a static token by adding a subject field
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
We are transforming how we structure our class names and data attributes definitions for all components. They are now all set in the same place.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Replaced deprecated uses of `@backstage/backend-common` with the equivalents in `@backstage/backend-defaults` and `@backstage/backend-plugin-api`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
Added placeholder prop to TextField component.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/backend-defaults': patch
'@backstage/integration': patch
---
UrlReader: Fix handling of access tokens for GitLab readURL requests
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
---
Fixing the typescript issue with using `z.unknown()`
-21
View File
@@ -1,21 +0,0 @@
---
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Added support for file deletion to `publish:github:pull-request` action.
Example usage:
```diff
- action: publish:github:pull-request
id: clean-up-pr
input:
description: This is the description
+ filesToDelete:
+ - outdated/changelog.md
+ - sample-file.txt
owner: owner
repo: repo
title: Title Goes Here
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-import': patch
---
Fixed bug with error message since ResponseError is now thrown from CatalogClient
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/canon': patch
---
adding export for ButtonLink so it's importable
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/integration-react': patch
---
Separated gitlab `write_repository` and `api` scope to pass checks in `RefreshingAuthSessionManager`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search-backend': patch
---
Error messages should not contain backend SQL query strings in the API response, this change will ensure that messages are logged and empty response is returned to the user
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/backend-defaults': patch
'@backstage/integration': patch
---
Fixed bug where the GitLab user token and GitLab integration token were being merged together
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/theme': patch
---
Update uncomfortably bright color in recently visited and top visited home page cards
+1 -1
View File
@@ -7,7 +7,7 @@
**/.git/**
**/public/**
**/microsite/**
**/canon-docs/**
**/docs-ui/**
**/templates/**
**/sample-templates/**
playwright.config.ts
+1
View File
@@ -40,6 +40,7 @@ yarn.lock @backstage/maintainers @backst
/packages/repo-tools @backstage/tooling-maintainers
/packages/techdocs-cli @backstage/techdocs-maintainers
/packages/techdocs-cli-embedded-app @backstage/techdocs-maintainers
/packages/ui @backstage/design-system-maintainers
/packages/yarn-plugin @backstage/tooling-maintainers
/plugins/app @backstage/framework-maintainers
/plugins/app-* @backstage/framework-maintainers
@@ -10,6 +10,7 @@ Airbrakes
ajv
Alaria
Alef
allowedHosts
allowlisted
Anddddd
Apdex
@@ -43,6 +44,7 @@ bugfixes
builtins
bundler
bundlers
bursty
callout
CDNs
Chai
@@ -102,6 +104,8 @@ deliverables
denormalized
dependabot
deps
dequeue
dequeueing
deserialization
destructured
destructuring
@@ -111,8 +115,6 @@ devcontainer
devcontainers
devops
devs
dequeue
dequeueing
dialogs
disambiguator
discoverability
@@ -150,8 +152,8 @@ FireHydrant
Firekube
Firestore
Fiverr
Flightcontrol
flightcontrol
Flightcontrol
Francesco
Frontside
Gaurav
@@ -175,8 +177,8 @@ Hackathons
haproxy
hardcoded
hardcoding
Harness
harness
Harness
Helidon
Henneke
Heroku
@@ -199,9 +201,10 @@ Indal
indexable
ingestors
inlined
inlining
inlinehilite
inlining
integrator's
intellij
interop
interoperate
iterable
@@ -312,8 +315,8 @@ OpenSearch
OpenShift
openssl
orgs
Overridable
overridable
Overridable
padding
paddings
pagerduty
@@ -380,10 +383,10 @@ retryable
reusability
Reusability
roadmaps
rollbar
rollout
Roboto
rollbar
Rollbar
rollout
Rollup
routable
Routable
@@ -399,9 +402,10 @@ sanitization
scaffolded
scaffolder
Scaffolder
scrollbar
SCM
SCMs
scrollable
scrollbar
sdks
seb
semlas
@@ -409,14 +413,15 @@ semver
sendmail
serializable
Serverless
severities
shoutout
SIG
signoff
SIGs
siloed
Sinon
snackbars
snackbar
snackbars
Snyk
Sonarqube
sourcemaps
@@ -487,6 +492,7 @@ transpiled
transpiler
transpilers
truthy
tsconfig
TSDoc
typeahead
ui
@@ -537,7 +543,3 @@ zod
Zolotusky
zoomable
zsh
scrollable
severities
intellij
tsconfig
@@ -23,7 +23,7 @@ jobs:
comment-cache-key: ${{ steps.hash.outputs.COMMENT_FILE_HASH }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
disable-sudo: true
egress-policy: block
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -40,7 +40,7 @@ jobs:
name: Test ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+6 -2
View File
@@ -28,7 +28,7 @@ jobs:
name: Install ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -64,7 +64,7 @@ jobs:
name: Verify ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -131,6 +131,10 @@ jobs:
- name: build canon
run: yarn --cwd packages/canon build
# For now BUI has a custom build script and needs to be built separately
- name: build BUI
run: yarn --cwd packages/ui build
- name: verify type dependencies
run: yarn lint:type-deps
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+3 -3
View File
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -135,7 +135,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -246,7 +246,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+5 -1
View File
@@ -114,6 +114,10 @@ jobs:
- name: build canon
run: yarn --cwd packages/canon build
# For now BUI has a custom build script and needs to be built separately
- name: build BUI
run: yarn --cwd packages/ui build
- name: verify type dependencies
run: yarn lint:type-deps
@@ -151,7 +155,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
if: github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps:
# Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+12 -12
View File
@@ -4,11 +4,11 @@ on:
branches: [master]
jobs:
sync-canon-docs:
sync-docs-ui:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -26,11 +26,11 @@ jobs:
with:
cache-prefix: ${{ runner.os }}-v20.x
- name: Checkout backstage/canon-docs
- name: Checkout backstage/docs-ui
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: backstage/canon-docs
path: canon-external-docs
repository: backstage/docs-ui
path: bui-external-docs
token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
- name: Configure Git
@@ -39,22 +39,22 @@ jobs:
git config --global user.name 'Github Canon Docs workflow'
- name: Install dependencies
working-directory: canon-docs
working-directory: docs-ui
run: yarn install
- name: Build Canon Docs
working-directory: canon-docs
- name: Build Docs UI
working-directory: docs-ui
run: |
yarn build
- name: Replace contents of canon-external-docs repo with docs build output
working-directory: canon-external-docs
- name: Replace contents of bui-external-docs repo with docs build output
working-directory: bui-external-docs
run: |
git rm -rf .
cp -R ../canon-docs/dist/. .
cp -R ../docs-ui/dist/. .
- name: Commit to canon-storybook repo
working-directory: canon-external-docs
working-directory: bui-external-docs
run: |
git add .
git commit -am "Canon Docs build for backstage/backstage@${{ github.sha }}"
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -11,7 +11,7 @@ jobs:
if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -11,7 +11,7 @@ jobs:
if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
name: E2E Linux ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
name: E2E Linux ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
name: Techdocs
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -25,7 +25,7 @@ jobs:
name: E2E Windows ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
name: E2E Windows ${{ matrix.node-version }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
name: Microsite
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+3 -3
View File
@@ -28,7 +28,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -137,7 +137,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -240,7 +240,7 @@ jobs:
name: Microsite
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
name: Storybook
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+4 -4
View File
@@ -28,7 +28,7 @@ jobs:
name: Storybook
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
@@ -49,10 +49,10 @@ jobs:
run: yarn install --immutable
working-directory: storybook
# Only for verification, the canon one is what we upload to Chromatic
# Only for verification, the BUI one is what we upload to Chromatic
- run: yarn build-storybook
- run: yarn --cwd packages/canon build-storybook
- run: yarn --cwd packages/ui build-storybook
- uses: chromaui/action@1cfa065cbdab28f6ca3afaeb3d761383076a35aa # v11
with:
@@ -60,5 +60,5 @@ jobs:
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
# https://www.chromatic.com/docs/custom-ci-provider#run-chromatic-on-external-forks-of-open-source-projects
projectToken: chpt_dab72dc0f97d55b
workingDir: packages/canon
workingDir: packages/ui
storybookBuildDir: storybook-static
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
+4 -4
View File
@@ -1,10 +1,10 @@
.yarn
dist
microsite
canon-docs/.next
canon-docs/public
canon-docs/out
packages/canon/css
docs-ui/.next
docs-ui/public
docs-ui/out
packages/ui/css
coverage
*.hbs
templates
-1
View File
@@ -1 +0,0 @@
canon.backstage.io
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long
-34
View File
@@ -1,34 +0,0 @@
const fs = require('fs');
const path = require('path');
const { bundle } = require('lightningcss');
const source = '../../packages/canon/src/css';
const destination = '../public';
const source1 = path.join(__dirname, `${source}/styles.css`);
const destination1 = path.join(__dirname, `${destination}/styles.css`);
// Function to bundle and copy the CSS file
const bundleAndCopyFile = async (source, destination) => {
try {
const result = await bundle({
filename: source,
minify: true,
});
fs.writeFileSync(destination, result.code);
console.log('File bundled and copied successfully!');
} catch (err) {
console.error('Error bundling file:', err);
}
};
// Initial bundle and copy
Promise.all([bundleAndCopyFile(source1, destination1)])
.then(() => {
// Add an empty line after all operations are complete - It looks better in the terminal :)
console.log('');
})
.catch(err => {
console.error('Error in processing files:', err);
});
@@ -1,43 +0,0 @@
import { changelog } from '@/utils/changelog';
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import { formattedMDXComponents } from '@/mdx-components';
export function Changelog() {
// Group changelog entries by version
const groupedChangelog = changelog.reduce((acc, entry) => {
if (!acc[entry.version]) {
acc[entry.version] = [];
}
acc[entry.version].push(entry);
return acc;
}, {} as Record<string, typeof changelog>);
// Sort versions in descending order
const sortedVersions = Object.keys(groupedChangelog).sort((a, b) =>
b.localeCompare(a),
);
const content = sortedVersions
.map(version => {
const entries = groupedChangelog[version];
return `## Version ${version}
${entries
.map(e => {
const prs =
e.prs.length > 0 &&
e.prs
.map(
pr =>
`[#${pr}](https://github.com/backstage/backstage/pull/${pr})`,
)
.join(', ');
return `- ${e.description} ${prs}`;
})
.join('\n')}`;
})
.join('\n');
return <MDXRemote components={formattedMDXComponents} source={content} />;
}
@@ -1,39 +0,0 @@
import styles from './Sidebar.module.css';
import { Docs } from './docs';
import { Playground } from './playground';
import Link from 'next/link';
import { ScrollArea } from '@base-ui-components/react/scroll-area';
export const Sidebar = () => {
return (
<div className={styles.sidebar}>
<ScrollArea.Root className={styles.root}>
<ScrollArea.Viewport className={styles.viewport}>
<div className={styles.content}>
<div className={styles.logoContainer}>
<Link href="/">
<svg
width="89"
height="27"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={styles.logo}
>
<path d="M77.414 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.086 0 1.9.352 2.442 1.056.558.689.836 1.598.836 2.728v7.502H84.41v-6.6c0-.66-.117-1.159-.352-1.496-.234-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM69.868 21.04c-1.13 0-2.142-.257-3.036-.77a5.547 5.547 0 0 1-2.068-2.09c-.484-.895-.726-1.892-.726-2.992 0-1.115.242-2.112.726-2.992a5.503 5.503 0 0 1 2.068-2.112c.88-.514 1.892-.77 3.036-.77 1.144 0 2.156.256 3.036.77a5.347 5.347 0 0 1 2.046 2.112c.498.88.748 1.87.748 2.97 0 1.114-.25 2.12-.748 3.014a5.343 5.343 0 0 1-2.068 2.09c-.88.513-1.885.77-3.014.77Zm0-2.618c.557 0 1.048-.132 1.474-.396a2.79 2.79 0 0 0 .99-1.144c.234-.499.352-1.064.352-1.694 0-.63-.118-1.188-.352-1.672a2.764 2.764 0 0 0-.99-1.166c-.426-.279-.917-.418-1.474-.418-.558 0-1.05.14-1.474.418a2.764 2.764 0 0 0-.99 1.166c-.22.484-.33 1.041-.33 1.672 0 .63.11 1.195.33 1.694.234.484.564.865.99 1.144.425.264.916.396 1.474.396ZM52.385 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.085 0 1.9.352 2.442 1.056.557.689.836 1.598.836 2.728v7.502h-3.036v-6.6c0-.66-.117-1.159-.352-1.496-.235-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM43.904 20.952c-1.026 0-1.87-.308-2.53-.924-.66-.616-.99-1.416-.99-2.398 0-1.115.418-2.01 1.254-2.684.85-.69 2.105-1.034 3.762-1.034h2.75l-.924.352v-.462c0-.572-.176-1.02-.528-1.342-.352-.338-.931-.506-1.738-.506-.69 0-1.386.154-2.09.462-.704.308-1.29.69-1.76 1.144v-2.882c.47-.352 1.1-.66 1.892-.924a7.942 7.942 0 0 1 2.486-.396c1.599 0 2.78.41 3.542 1.232.778.806 1.166 1.914 1.166 3.322v5.742c0 .176.008.352.022.528.03.161.066.322.11.484h-3.014v-3.3l.044 1.386a4.044 4.044 0 0 1-1.32 1.606c-.572.396-1.283.594-2.134.594Zm.858-2.156c.558 0 1.049-.206 1.474-.616.44-.426.77-.954.99-1.584v-.792h-1.562c-.762 0-1.334.146-1.716.44-.381.278-.572.674-.572 1.188 0 .41.125.74.374.99.264.25.602.374 1.012.374ZM34.66 21.04c-1.525 0-2.874-.345-4.047-1.034-1.174-.704-2.09-1.68-2.75-2.926-.646-1.247-.968-2.662-.968-4.246 0-1.584.322-2.992.968-4.224.66-1.232 1.576-2.193 2.75-2.882 1.173-.704 2.522-1.056 4.048-1.056.968 0 1.818.11 2.552.33.748.22 1.356.506 1.826.858v3.498c-.396-.484-.96-.895-1.694-1.232-.719-.338-1.51-.506-2.376-.506-.939 0-1.775.22-2.508.66-.719.44-1.284 1.056-1.694 1.848-.396.792-.594 1.694-.594 2.706 0 1.026.198 1.943.594 2.75.41.792.975 1.408 1.694 1.848.733.44 1.57.66 2.508.66.88 0 1.68-.162 2.398-.484.718-.323 1.276-.726 1.672-1.21v3.41a5.686 5.686 0 0 1-1.87.902c-.704.22-1.54.33-2.508.33ZM11.275 6.271c.276.526.019 1.152-.464 1.498a5.846 5.846 0 0 0 1.004 10.082c.454.205.789.632.789 1.13v6.206a.837.837 0 0 1-.838.837C5.33 26.024.112 20.804.112 14.366V.862C.112.399.487.024.95.024c4.483 0 8.376 2.533 10.325 6.247Z" />
<path d="M14.037 16.729a4.237 4.237 0 0 0 4.234-4.24 4.237 4.237 0 0 0-4.234-4.242 4.237 4.237 0 0 0-4.234 4.241 4.237 4.237 0 0 0 4.234 4.24Z" />
</svg>
</Link>
</div>
<div className={styles.menu}>
<Docs />
<Playground />
</div>
</div>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar className={styles.scrollbar}>
<ScrollArea.Thumb className={styles.thumb} />
</ScrollArea.Scrollbar>
</ScrollArea.Root>
</div>
);
};
@@ -1,27 +0,0 @@
.root {
margin-top: 40px;
}
.list {
display: flex;
gap: var(--canon-space-6);
border-bottom: 1px solid var(--border);
position: relative;
margin-bottom: var(--canon-space-6);
}
.tab {
all: unset;
cursor: pointer;
padding-bottom: 8px;
}
.indicator {
position: absolute;
bottom: -1px;
left: var(--active-tab-left);
width: var(--active-tab-width);
height: 1px;
background-color: var(--primary);
transition: all 0.2s ease-in-out;
}
@@ -0,0 +1,85 @@
# Catalog Read-Write Split
This article gives an overview of how you might split your catalog deployment into two - one which handles only reads (the read part of the API), and another that handles everything else (the write part of the API, and processing and ingestion etc).
This is useful for several reasons:
- The performance characteristics and scaling needs of those two concerns typically differ significantly
- Moving the bursty processing and ingestion load on a separate deployment can make the important read part of the API have more deterministic response times
- It opens up for easier cross region deployment of read nodes, while having write nodes in a single "home" region
- It also opens up for primary/secondary split of the underlying database, with streaming replication
## Overview
This is a rough overview of what we will go through:
- Ensure that all frontend code uses `catalogApiRef`, and all backend code uses `catalogServiceRef`, for talking to the catalog
- Add a separate discovery name for the write deployment
- Register both frontend and backend implementations of the catalog client that know to send traffic to the right discovery name as needed
- Set up the backend itself with dedicated read and write configuration
- Split the deployment into two
- Follow up with a database split, if desired
## 1. Prerequisite: Establish usage of catalog client refs
First, ensure that all of your code uses _injected_ catalog clients for its catalog communications needs instead of making their own with `new`. For frontend code that means leveraging `catalogApiRef`, and for backend it means leveraging `catalogServiceRef`. This is what enables the sort of wholesale injection of custom behaviors that we are about to do, and is a strongly recommended best practice either way.
- ✅ Search through your projects and ensure that there are no `new CatalogClient` calls. If you find any, consider rewriting that code to instead having the client injected through leveraging the corresponding ref.
- ✅ Search through your projects and ensure that you do _not_ import the `catalogServiceRef` that specifically is in the `@backstage/plugin-catalog-node/alpha` export. That one has been deprecated for a long time and will not be targeted by this guide. If you find any, consider rewriting that code to instead inject the client from `@backstage/plugin-catalog-node` (note the lack of `/alpha`).
> [!TIP]
> If you find usages of `new CatalogClient` in tests, you can normally leave those as-is. You can however consider to later try out the `catalogApiMock` from `@backstage/plugin-catalog-react/testUtils` for frontend tests, and `catalogServiceMock` from `@backstage/plugin-catalog-node/testUtils` for backend tests. These allow you to inject a client that behaves like a complete fake catalog backend with entities in it, without complex mocking.
## 2. Decide your deployment split structure
We will be defining a fake plugin ID called `catalog-write`. In addition to your current single catalog deployment you will add a second one that receives traffic for `catalog-write`. You need to decide upon what your ingress to those two deployments will look like. This is highly company dependent, so we cannot give general guidance.
This guide will however NOT split the code base into two. It will instead change your catalog backend code in such a way that it can support either deployment. This is all very flexible and you can tweak it as you see fit, but that's what worked well for us.
This guide will assume that when all is said and done, requests for the `catalog` plugin ID resolve to the URL `https://catalog-read.example.net/api/catalog`, and requests for the `catalog-write` plugin ID resolve to the URL `https://catalog-write.example.net/api/catalog`. This is just for illustration and you shall change these to their actual correct values at your company.
- ✅ Copy the contents of [the `app-config.yaml` file](./workspace/app-config.yaml) to your own. We will assume that these exact settings are applied both to your frontend and your catalog (read AND write) deployment. For now, if you are applying this guide step by step rather than all at once, you can set the URLs in there to point to your good old pre-split deployment and only update them again after the split.
> [!TIP]
> As a future refactor, you could instead break out this behavior into a custom injected discovery implementation in a library that all your projects can import. That takes a few more steps and is left as a separate exercise. If you already have such a library in your internal NPM, feel free to put it there to begin with and import from there.
## 3. Get split-aware catalog clients in place
Now let's put clients in place whose methods send traffic to either `catalog` or `catalog-write` as needed.
- ✅ Copy [the `catalogApi.ts` file](./workspace/packages/app/src/catalogApi.ts) into your `packages/app/src` directory of the project where you develop your Backstage frontend. Then reference that file's API factory in your `packages/app/src/apis.ts` file, [as illustrated here](./workspace/packages/app/src/apis.ts).
- ✅ Copy [the `catalogService.ts` file](./workspace/packages/backend/src/catalogService.ts) into your `packages/backend/src` directory of the project where you develop your Software Catalog backend. We will reference the file itself in the step below.
After step 4 below is complete, these will be automatically picked up and used by all callers.
> [!TIP]
> As a future refactor, you could instead break out these clients into a node and a react library that all your projects can import. That takes a few more steps and is left as a separate exercise. If you already have such libraries in your internal NPM, feel free to put them there to begin with and import from there.
## 4. Split the catalog backend
We'll now perform the actual split of the catalog backend. You will make separate config files that apply to each, and adapt the backend code to handle both cases seamlessly.
- ✅ Duplicate your deployment. It's highly company dependent how this is done. Some may for example duplicate some declarative `Deployment` and `Service` k8s manifests etc, but it depends.
- ✅ Copy [the `app-config.catalog-read.yaml`] and [the `app-config.catalog-write.yaml`] files into your project root. You must set up your read and write deployments to load their respective files with the `--config` flag, _in addition to_ the `app-config.yaml` file and possibly `app-config.production.yaml` that they already loaded.
- ✅ Copy [the `config.d.ts`](./workspace/config.d.ts) file to your catalog backend directory at `packages/backend`. You should refer to it in the `package.json`'s `"files"` and `"configSchema"` fields [as per usual](https://backstage.io/docs/conf/defining).
- ✅ Update your `packages/backend/src/index.ts` file to match [the proposed structure here](./workspace/packages/backend/src/index.ts). Note how it applies the custom catalog service we copied in the previous step, and has a separate section for write-only concerns.
## 5. Region and database split
After the above is deployed and working, you are well set up for some next step.
- Scaling your readers across multiple regions and add geo-aware routing to them, while keeping writers in a "home" region
- Splitting the database server into a primary that the write nodes connect to, and regional secondaries with streaming replication from the primary
But all of this is left as an exercise for the reader.
## 6. Help make this smoother
Congratulations on successfully performing your split!
We would love [some help](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) with making this process easier for others. For example, if read nodes could automatically transparently proxy traffic to write nodes as needed, we would need far less fiddling with clients at a relatively small extra cost.
@@ -0,0 +1,12 @@
# This file should be given to the catalog read nodes.
backend:
database:
# disable running database migrations for every plugin/module
skipMigrations: true
catalog:
role: read
# disable processing engine
processingInterval: false
@@ -0,0 +1,4 @@
# This file should be given to the catalog write nodes.
catalog:
role: write
@@ -0,0 +1,19 @@
# This is in your regular app-config.
# This introduces a made-up "catalog-write" plugin ID that the frontend catalog
# API implementation can use to resolve where to find the write nodes.
discovery:
endpoints:
#
# TODO: Replace with actual URLs
#
# NOTE: Each target can also be an object with "internal" and "external"
# keys with different URLs, if they should be different when called by
# backends and the frontend, respectively.
#
- target: https://catalog-read.example.net/api/catalog
plugins:
- catalog
- target: https://catalog-write.example.net/api/catalog
plugins:
- catalog-write
@@ -0,0 +1,5 @@
export interface Config {
catalog: {
role: 'read' | 'write';
};
}
@@ -0,0 +1,11 @@
import { AnyApiFactory } from '@backstage/core-plugin-api';
import { catalogApiFactory } from './catalogApi';
// This file is already present in a typical Backstage app. We are just adding
// the catalog API factory here to ensure that the frontend sends requests to
// the correct set of catalog nodes depending on whether it's a read or a write
// operation.
export const apis: AnyApiFactory[] = [
// ...other APIs here...
catalogApiFactory,
];
@@ -0,0 +1,174 @@
import {
AddLocationRequest,
AddLocationResponse,
CatalogApi,
CatalogClient,
CatalogRequestOptions,
GetEntitiesByRefsRequest,
GetEntitiesByRefsResponse,
GetEntitiesRequest,
GetEntitiesResponse,
GetEntityAncestorsRequest,
GetEntityAncestorsResponse,
GetEntityFacetsRequest,
GetEntityFacetsResponse,
GetLocationsResponse,
Location,
QueryEntitiesRequest,
QueryEntitiesResponse,
ValidateEntityResponse,
} from '@backstage/catalog-client';
import { CompoundEntityRef, Entity } from '@backstage/catalog-model';
import {
createApiFactory,
DiscoveryApi,
discoveryApiRef,
FetchApi,
fetchApiRef,
} from '@backstage/core-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
/**
* Implements the catalog client for frontends, by using a custom service
* discovery to achieve read/write segregation.
*/
export class ReadWriteSplitCatalogClient implements CatalogApi {
#write: CatalogApi;
#read: CatalogApi;
constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {
this.#read = new CatalogClient({
fetchApi: options.fetchApi,
discoveryApi: {
// This uses the normal "catalog" plugin ID
getBaseUrl: () => options.discoveryApi.getBaseUrl('catalog'),
},
});
this.#write = new CatalogClient({
fetchApi: options.fetchApi,
discoveryApi: {
// This uses the made-up "catalog-write" plugin ID (see app-config.yaml
// which defines a custom discovery endpoint for this)
getBaseUrl: () => options.discoveryApi.getBaseUrl('catalog-write'),
},
});
}
getEntities(
request?: GetEntitiesRequest,
options?: CatalogRequestOptions,
): Promise<GetEntitiesResponse> {
return this.#read.getEntities(request, options);
}
getEntitiesByRefs(
request: GetEntitiesByRefsRequest,
options?: CatalogRequestOptions,
): Promise<GetEntitiesByRefsResponse> {
return this.#read.getEntitiesByRefs(request, options);
}
queryEntities(
request?: QueryEntitiesRequest,
options?: CatalogRequestOptions,
): Promise<QueryEntitiesResponse> {
return this.#read.queryEntities(request, options);
}
getEntityAncestors(
request: GetEntityAncestorsRequest,
options?: CatalogRequestOptions,
): Promise<GetEntityAncestorsResponse> {
return this.#read.getEntityAncestors(request, options);
}
getEntityByRef(
entityRef: string | CompoundEntityRef,
options?: CatalogRequestOptions,
): Promise<Entity | undefined> {
return this.#read.getEntityByRef(entityRef, options);
}
removeEntityByUid(
uid: string,
options?: CatalogRequestOptions,
): Promise<void> {
return this.#write.removeEntityByUid(uid, options);
}
refreshEntity(
entityRef: string,
options?: CatalogRequestOptions,
): Promise<void> {
return this.#write.refreshEntity(entityRef, options);
}
getEntityFacets(
request: GetEntityFacetsRequest,
options?: CatalogRequestOptions,
): Promise<GetEntityFacetsResponse> {
return this.#read.getEntityFacets(request, options);
}
getLocations(
request?: {},
options?: CatalogRequestOptions,
): Promise<GetLocationsResponse> {
return this.#read.getLocations(request, options);
}
getLocationById(
id: string,
options?: CatalogRequestOptions,
): Promise<Location | undefined> {
return this.#read.getLocationById(id, options);
}
getLocationByRef(
locationRef: string,
options?: CatalogRequestOptions,
): Promise<Location | undefined> {
return this.#read.getLocationByRef(locationRef, options);
}
addLocation(
location: AddLocationRequest,
options?: CatalogRequestOptions,
): Promise<AddLocationResponse> {
return this.#write.addLocation(location, options);
}
removeLocationById(
id: string,
options?: CatalogRequestOptions,
): Promise<void> {
return this.#write.removeLocationById(id, options);
}
getLocationByEntity(
entityRef: string | CompoundEntityRef,
options?: CatalogRequestOptions,
): Promise<Location | undefined> {
return this.#read.getLocationByEntity(entityRef, options);
}
validateEntity(
entity: Entity,
locationRef: string,
options?: CatalogRequestOptions,
): Promise<ValidateEntityResponse> {
return this.#write.validateEntity(entity, locationRef, options);
}
}
// You should pass this to createApp.
export const catalogApiFactory = createApiFactory({
api: catalogApiRef,
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
factory: ({ discoveryApi, fetchApi }) => {
return new ReadWriteSplitCatalogClient({
discoveryApi,
fetchApi,
});
},
});
@@ -0,0 +1,231 @@
import {
AuthService,
coreServices,
createServiceFactory,
DiscoveryService,
} from '@backstage/backend-plugin-api';
import {
AddLocationRequest,
AddLocationResponse,
CatalogApi,
CatalogClient,
CatalogRequestOptions,
GetEntitiesByRefsRequest,
GetEntitiesByRefsResponse,
GetEntitiesRequest,
GetEntitiesResponse,
GetEntityAncestorsRequest,
GetEntityAncestorsResponse,
GetEntityFacetsRequest,
GetEntityFacetsResponse,
GetLocationsResponse,
Location,
QueryEntitiesRequest,
QueryEntitiesResponse,
ValidateEntityResponse,
} from '@backstage/catalog-client';
import { CompoundEntityRef, Entity } from '@backstage/catalog-model';
import {
CatalogService,
CatalogServiceRequestOptions,
catalogServiceRef,
} from '@backstage/plugin-catalog-node';
/**
* Implements the catalog client for backends, by using a custom service
* discovery to achieve read/write segregation.
*/
export class ReadWriteSplitCatalogService implements CatalogService {
readonly #auth: AuthService;
readonly #catalogRead: CatalogApi;
readonly #catalogWrite: CatalogApi;
constructor(options: { auth: AuthService; discovery: DiscoveryService }) {
this.#auth = options.auth;
this.#catalogRead = new CatalogClient({
discoveryApi: {
// This uses the normal "catalog" plugin ID
getBaseUrl: () => options.discovery.getBaseUrl('catalog'),
},
});
this.#catalogWrite = new CatalogClient({
discoveryApi: {
// This uses the made-up "catalog-write" plugin ID (see app-config.yaml
// which defines a custom discovery endpoint for this)
getBaseUrl: () => options.discovery.getBaseUrl('catalog-write'),
},
});
}
async getEntities(
request: GetEntitiesRequest | undefined,
options: CatalogServiceRequestOptions,
): Promise<GetEntitiesResponse> {
return this.#catalogRead.getEntities(
request,
await this.#getOptions(options),
);
}
async getEntitiesByRefs(
request: GetEntitiesByRefsRequest,
options: CatalogServiceRequestOptions,
): Promise<GetEntitiesByRefsResponse> {
return this.#catalogRead.getEntitiesByRefs(
request,
await this.#getOptions(options),
);
}
async queryEntities(
request: QueryEntitiesRequest | undefined,
options: CatalogServiceRequestOptions,
): Promise<QueryEntitiesResponse> {
return this.#catalogRead.queryEntities(
request,
await this.#getOptions(options),
);
}
async getEntityAncestors(
request: GetEntityAncestorsRequest,
options: CatalogServiceRequestOptions,
): Promise<GetEntityAncestorsResponse> {
return this.#catalogRead.getEntityAncestors(
request,
await this.#getOptions(options),
);
}
async getEntityByRef(
entityRef: string | CompoundEntityRef,
options: CatalogServiceRequestOptions,
): Promise<Entity | undefined> {
return this.#catalogRead.getEntityByRef(
entityRef,
await this.#getOptions(options),
);
}
async removeEntityByUid(
uid: string,
options: CatalogServiceRequestOptions,
): Promise<void> {
return this.#catalogWrite.removeEntityByUid(
uid,
await this.#getOptions(options),
);
}
async refreshEntity(
entityRef: string,
options: CatalogServiceRequestOptions,
): Promise<void> {
return this.#catalogWrite.refreshEntity(
entityRef,
await this.#getOptions(options),
);
}
async getEntityFacets(
request: GetEntityFacetsRequest,
options: CatalogServiceRequestOptions,
): Promise<GetEntityFacetsResponse> {
return this.#catalogRead.getEntityFacets(
request,
await this.#getOptions(options),
);
}
async getLocations(
options: CatalogRequestOptions,
): Promise<GetLocationsResponse> {
return this.#catalogRead.getLocations(options);
}
async getLocationById(
id: string,
options: CatalogServiceRequestOptions,
): Promise<Location | undefined> {
return this.#catalogRead.getLocationById(
id,
await this.#getOptions(options),
);
}
async getLocationByRef(
locationRef: string,
options: CatalogServiceRequestOptions,
): Promise<Location | undefined> {
return this.#catalogRead.getLocationByRef(
locationRef,
await this.#getOptions(options),
);
}
async addLocation(
location: AddLocationRequest,
options: CatalogServiceRequestOptions,
): Promise<AddLocationResponse> {
return this.#catalogWrite.addLocation(
location,
await this.#getOptions(options),
);
}
async removeLocationById(
id: string,
options: CatalogServiceRequestOptions,
): Promise<void> {
return this.#catalogWrite.removeLocationById(
id,
await this.#getOptions(options),
);
}
async getLocationByEntity(
entityRef: string | CompoundEntityRef,
options: CatalogServiceRequestOptions,
): Promise<Location | undefined> {
return this.#catalogRead.getLocationByEntity(
entityRef,
await this.#getOptions(options),
);
}
async validateEntity(
entity: Entity,
locationRef: string,
options: CatalogServiceRequestOptions,
): Promise<ValidateEntityResponse> {
return this.#catalogWrite.validateEntity(
entity,
locationRef,
await this.#getOptions(options),
);
}
async #getOptions(
options: CatalogServiceRequestOptions,
): Promise<CatalogRequestOptions> {
return this.#auth.getPluginRequestToken({
onBehalfOf: options.credentials,
targetPluginId: 'catalog',
});
}
}
// You should register this in your backend.
export const catalogService = createServiceFactory({
service: catalogServiceRef,
deps: {
auth: coreServices.auth,
discovery: coreServices.discovery,
},
async factory({ auth, discovery }) {
return new ReadWriteSplitCatalogService({
auth,
discovery,
});
},
});
@@ -0,0 +1,34 @@
import { createBackend } from '@backstage/backend-defaults';
import {
coreServices,
createBackendFeatureLoader,
} from '@backstage/backend-plugin-api';
import { catalogService } from './catalogService';
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(catalogService);
// Here at the root level, you can add more features that you want to apply to
// BOTH the read and write nodes, as needed.
backend.add(
createBackendFeatureLoader({
deps: { config: coreServices.rootConfig },
async *loader({ config }) {
if (config.getString('catalog.role') !== 'write') {
return;
}
// Here inside the loader, you can add more features that you want to
// apply to ONLY the write nodes, as needed. This is where providers and
// processors go, for example. The incremental ingestion provider line
// below is just an example.
yield import(
'@backstage/plugin-catalog-backend-module-incremental-ingestion'
);
},
}),
);
backend.start();
+2 -2
View File
@@ -1,6 +1,6 @@
# Canon Docs
# Backstage UI Docs
Canon is our internal UI library built for Backstage. We built this website to document the library and its components. You can view this website [here](https://canon.backstage.io).
Backstage UI is our internal UI library built for Backstage. We built this website to document the library and its components. You can view this website [here](https://ui.backstage.io).
## How to run locally
@@ -1,12 +1,15 @@
{
"name": "canon-docs",
"name": "docs-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "npm run build:css && next build",
"build:css": "node scripts/build-css.js",
"prebuild": "yarn sync:css",
"build": "next build",
"lint": "next lint",
"start": "npm run build:css && next dev"
"prestart": "yarn sync:css",
"start": "concurrently \"yarn sync:css:watch\" \"next dev\"",
"sync:css": "node scripts/sync-css.js",
"sync:css:watch": "node scripts/sync-css.js --watch"
},
"resolutions": {
"@types/react": "19.1.8",
@@ -14,6 +17,7 @@
},
"dependencies": {
"@codemirror/lang-sass": "^6.0.2",
"@codemirror/view": "^6.34.4",
"@lezer/highlight": "^1.2.1",
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
@@ -25,6 +29,7 @@
"motion": "^12.4.1",
"next": "15.3.4",
"next-mdx-remote-client": "^2.1.2",
"prop-types": "^15.8.1",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-frame-component": "^5.2.7",
@@ -36,6 +41,8 @@
"@types/node": "^20",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"chokidar": "^3.6.0",
"concurrently": "^8.2.2",
"eslint": "^8",
"eslint-config-next": "15.3.4",
"lightningcss": "^1.28.2",
+1
View File
@@ -0,0 +1 @@
ui.backstage.io

Some files were not shown because too many files have changed in this diff Show More