Merge branch 'master' into stack-overflow-plugin-fix

This commit is contained in:
Tommy Le
2024-01-17 08:09:14 +01:00
728 changed files with 17696 additions and 1968 deletions
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Fixed an issue where some Okta's resolvers were missing
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-react': patch
---
Scaffolder form now shows a list of errors at the top of the form.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-components': patch
---
Fixed bug in Link where it was possible to select and copy a hidden element into clipboard
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/create-app': patch
---
Bumped create-app version.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-azure-sites': patch
---
Show Azure site tags in `EntityAzureSitesOverviewWidget`.
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/cli': patch
---
Use sha256 instead of md5 in build script cache key calculation
Makes it possible to build on FIPS nodejs.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-plugin-api': patch
---
Removed unnecessary `i18next` dependency.
-8
View File
@@ -1,8 +0,0 @@
---
'@backstage/backend-common': patch
---
Use sha256 instead of md5 for hash key calculation in caches
This can have a side effect of invalidating caches (when cache key was >250 characters)
This improves compliance with FIPS nodejs
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-user-settings': minor
---
Updated the user settings selector to use a select component that displays native language names instead of language codes if possible.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-octopus-deploy': patch
---
added install path and fixed import on plugin-octopus-deploy
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/catalog-client': patch
---
Fix a bug in `getLocationByRef` that led to invalid backend calls
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/repo-tools': patch
---
Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it
-9
View File
@@ -1,9 +0,0 @@
---
'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch
'@backstage/config-loader': patch
'@backstage/create-app': patch
'@backstage/repo-tools': patch
'@backstage/cli-node': patch
---
Removed `mock-fs` dev dependency.
-8
View File
@@ -1,8 +0,0 @@
---
'@backstage/plugin-kubernetes-react': patch
'@backstage/plugin-kubernetes': patch
---
Add `authuser` search parameter to GKE cluster link formatter in k8s plugin
Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage.
-8
View File
@@ -1,8 +0,0 @@
---
'@backstage/plugin-search-backend-module-stack-overflow-collator': patch
'@backstage/plugin-search-backend-module-techdocs': patch
'@backstage/plugin-search-backend-module-catalog': patch
'@backstage/plugin-search-backend-module-explore': patch
---
Update wording to show that the backend system no longer is in alpha
-289
View File
@@ -1,289 +0,0 @@
{
"mode": "pre",
"tag": "next",
"initialVersions": {
"example-app": "0.2.90",
"@backstage/app-defaults": "1.4.6",
"example-app-next": "0.0.4",
"app-next-example-plugin": "0.0.4",
"example-backend": "0.2.90",
"@backstage/backend-app-api": "0.5.9",
"@backstage/backend-common": "0.20.0",
"@backstage/backend-defaults": "0.2.8",
"@backstage/backend-dev-utils": "0.1.2",
"example-backend-next": "0.0.18",
"@backstage/backend-openapi-utils": "0.1.1",
"@backstage/backend-plugin-api": "0.6.8",
"@backstage/backend-plugin-manager": "0.0.4",
"@backstage/backend-tasks": "0.5.13",
"@backstage/backend-test-utils": "0.2.9",
"@backstage/catalog-client": "1.5.0",
"@backstage/catalog-model": "1.4.3",
"@backstage/cli": "0.25.0",
"@backstage/cli-common": "0.1.13",
"@backstage/cli-node": "0.2.1",
"@backstage/codemods": "0.1.46",
"@backstage/config": "1.1.1",
"@backstage/config-loader": "1.6.0",
"@backstage/core-app-api": "1.11.2",
"@backstage/core-compat-api": "0.1.0",
"@backstage/core-components": "0.13.9",
"@backstage/core-plugin-api": "1.8.1",
"@backstage/create-app": "0.5.8",
"@backstage/dev-utils": "1.0.25",
"e2e-test": "0.2.10",
"@backstage/e2e-test-utils": "0.1.0",
"@backstage/errors": "1.2.3",
"@backstage/eslint-plugin": "0.1.4",
"@backstage/frontend-app-api": "0.4.0",
"@backstage/frontend-plugin-api": "0.4.0",
"@backstage/frontend-test-utils": "0.1.0",
"@backstage/integration": "1.8.0",
"@backstage/integration-aws-node": "0.1.8",
"@backstage/integration-react": "1.1.22",
"@backstage/release-manifests": "0.0.11",
"@backstage/repo-tools": "0.5.0",
"@techdocs/cli": "1.8.0",
"techdocs-cli-embedded-app": "0.2.89",
"@backstage/test-utils": "1.4.6",
"@backstage/theme": "0.5.0",
"@backstage/types": "1.1.1",
"@backstage/version-bridge": "1.0.7",
"@backstage/plugin-adr": "0.6.11",
"@backstage/plugin-adr-backend": "0.4.5",
"@backstage/plugin-adr-common": "0.2.18",
"@backstage/plugin-airbrake": "0.3.28",
"@backstage/plugin-airbrake-backend": "0.3.5",
"@backstage/plugin-allure": "0.1.44",
"@backstage/plugin-analytics-module-ga": "0.1.36",
"@backstage/plugin-analytics-module-ga4": "0.1.7",
"@backstage/plugin-analytics-module-newrelic-browser": "0.0.5",
"@backstage/plugin-apache-airflow": "0.2.18",
"@backstage/plugin-api-docs": "0.10.2",
"@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.5",
"@backstage/plugin-apollo-explorer": "0.1.18",
"@backstage/plugin-app-backend": "0.3.56",
"@backstage/plugin-app-node": "0.1.8",
"@backstage/plugin-auth-backend": "0.20.1",
"@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.0",
"@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.2",
"@backstage/plugin-auth-backend-module-github-provider": "0.1.5",
"@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.5",
"@backstage/plugin-auth-backend-module-google-provider": "0.1.5",
"@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.3",
"@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.5",
"@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.0",
"@backstage/plugin-auth-backend-module-okta-provider": "0.0.1",
"@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.2",
"@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.0",
"@backstage/plugin-auth-node": "0.4.2",
"@backstage/plugin-azure-devops": "0.3.10",
"@backstage/plugin-azure-devops-backend": "0.5.0",
"@backstage/plugin-azure-devops-common": "0.3.2",
"@backstage/plugin-azure-sites": "0.1.17",
"@backstage/plugin-azure-sites-backend": "0.1.18",
"@backstage/plugin-azure-sites-common": "0.1.1",
"@backstage/plugin-badges": "0.2.52",
"@backstage/plugin-badges-backend": "0.3.5",
"@backstage/plugin-bazaar": "0.2.20",
"@backstage/plugin-bazaar-backend": "0.3.6",
"@backstage/plugin-bitbucket-cloud-common": "0.2.15",
"@backstage/plugin-bitrise": "0.1.55",
"@backstage/plugin-catalog": "1.16.0",
"@backstage/plugin-catalog-backend": "1.16.0",
"@backstage/plugin-catalog-backend-module-aws": "0.3.2",
"@backstage/plugin-catalog-backend-module-azure": "0.1.27",
"@backstage/plugin-catalog-backend-module-backstage-openapi": "0.1.1",
"@backstage/plugin-catalog-backend-module-bitbucket": "0.2.23",
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.23",
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.21",
"@backstage/plugin-catalog-backend-module-gcp": "0.1.8",
"@backstage/plugin-catalog-backend-module-gerrit": "0.1.24",
"@backstage/plugin-catalog-backend-module-github": "0.4.6",
"@backstage/plugin-catalog-backend-module-github-org": "0.1.2",
"@backstage/plugin-catalog-backend-module-gitlab": "0.3.5",
"@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.12",
"@backstage/plugin-catalog-backend-module-ldap": "0.5.23",
"@backstage/plugin-catalog-backend-module-msgraph": "0.5.15",
"@backstage/plugin-catalog-backend-module-openapi": "0.1.25",
"@backstage/plugin-catalog-backend-module-puppetdb": "0.1.13",
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.5",
"@backstage/plugin-catalog-backend-module-unprocessed": "0.3.5",
"@backstage/plugin-catalog-common": "1.0.19",
"@backstage/plugin-catalog-graph": "0.3.2",
"@backstage/plugin-catalog-import": "0.10.4",
"@backstage/plugin-catalog-node": "1.6.0",
"@backstage/plugin-catalog-react": "1.9.2",
"@backstage/plugin-catalog-unprocessed-entities": "0.1.6",
"@backstage/plugin-cicd-statistics": "0.1.30",
"@backstage/plugin-cicd-statistics-module-gitlab": "0.1.24",
"@backstage/plugin-circleci": "0.3.28",
"@backstage/plugin-cloudbuild": "0.3.28",
"@backstage/plugin-code-climate": "0.1.28",
"@backstage/plugin-code-coverage": "0.2.21",
"@backstage/plugin-code-coverage-backend": "0.2.22",
"@backstage/plugin-codescene": "0.1.20",
"@backstage/plugin-config-schema": "0.1.48",
"@backstage/plugin-cost-insights": "0.12.17",
"@backstage/plugin-cost-insights-common": "0.1.2",
"@backstage/plugin-devtools": "0.1.7",
"@backstage/plugin-devtools-backend": "0.2.5",
"@backstage/plugin-devtools-common": "0.1.7",
"@backstage/plugin-dynatrace": "8.0.2",
"@backstage/plugin-entity-feedback": "0.2.11",
"@backstage/plugin-entity-feedback-backend": "0.2.5",
"@backstage/plugin-entity-feedback-common": "0.1.3",
"@backstage/plugin-entity-validation": "0.1.13",
"@backstage/plugin-events-backend": "0.2.17",
"@backstage/plugin-events-backend-module-aws-sqs": "0.2.11",
"@backstage/plugin-events-backend-module-azure": "0.1.18",
"@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.18",
"@backstage/plugin-events-backend-module-gerrit": "0.1.18",
"@backstage/plugin-events-backend-module-github": "0.1.18",
"@backstage/plugin-events-backend-module-gitlab": "0.1.18",
"@backstage/plugin-events-backend-test-utils": "0.1.18",
"@backstage/plugin-events-node": "0.2.17",
"@internal/plugin-todo-list": "1.0.20",
"@internal/plugin-todo-list-backend": "1.0.20",
"@internal/plugin-todo-list-common": "1.0.16",
"@backstage/plugin-explore": "0.4.14",
"@backstage/plugin-explore-backend": "0.0.18",
"@backstage/plugin-explore-common": "0.0.2",
"@backstage/plugin-explore-react": "0.0.34",
"@backstage/plugin-firehydrant": "0.2.12",
"@backstage/plugin-fossa": "0.2.60",
"@backstage/plugin-gcalendar": "0.3.21",
"@backstage/plugin-gcp-projects": "0.3.44",
"@backstage/plugin-git-release-manager": "0.3.40",
"@backstage/plugin-github-actions": "0.6.9",
"@backstage/plugin-github-deployments": "0.1.59",
"@backstage/plugin-github-issues": "0.2.17",
"@backstage/plugin-github-pull-requests-board": "0.1.22",
"@backstage/plugin-gitops-profiles": "0.3.43",
"@backstage/plugin-gocd": "0.1.34",
"@backstage/plugin-graphiql": "0.3.1",
"@backstage/plugin-graphql-voyager": "0.1.10",
"@backstage/plugin-home": "0.6.0",
"@backstage/plugin-home-react": "0.1.6",
"@backstage/plugin-ilert": "0.2.17",
"@backstage/plugin-jenkins": "0.9.3",
"@backstage/plugin-jenkins-backend": "0.3.2",
"@backstage/plugin-jenkins-common": "0.1.22",
"@backstage/plugin-kafka": "0.3.28",
"@backstage/plugin-kafka-backend": "0.3.6",
"@backstage/plugin-kubernetes": "0.11.3",
"@backstage/plugin-kubernetes-backend": "0.14.0",
"@backstage/plugin-kubernetes-cluster": "0.0.4",
"@backstage/plugin-kubernetes-common": "0.7.2",
"@backstage/plugin-kubernetes-node": "0.1.2",
"@backstage/plugin-kubernetes-react": "0.2.0",
"@backstage/plugin-lighthouse": "0.4.13",
"@backstage/plugin-lighthouse-backend": "0.4.0",
"@backstage/plugin-lighthouse-common": "0.1.4",
"@backstage/plugin-linguist": "0.1.13",
"@backstage/plugin-linguist-backend": "0.5.5",
"@backstage/plugin-linguist-common": "0.1.2",
"@backstage/plugin-microsoft-calendar": "0.1.10",
"@backstage/plugin-newrelic": "0.3.43",
"@backstage/plugin-newrelic-dashboard": "0.3.3",
"@backstage/plugin-nomad": "0.1.9",
"@backstage/plugin-nomad-backend": "0.1.10",
"@backstage/plugin-octopus-deploy": "0.2.10",
"@backstage/plugin-opencost": "0.2.3",
"@backstage/plugin-org": "0.6.18",
"@backstage/plugin-org-react": "0.1.17",
"@backstage/plugin-pagerduty": "0.7.0",
"@backstage/plugin-periskop": "0.1.26",
"@backstage/plugin-periskop-backend": "0.2.6",
"@backstage/plugin-permission-backend": "0.5.31",
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.5",
"@backstage/plugin-permission-common": "0.7.11",
"@backstage/plugin-permission-node": "0.7.19",
"@backstage/plugin-permission-react": "0.4.18",
"@backstage/plugin-playlist": "0.2.2",
"@backstage/plugin-playlist-backend": "0.3.12",
"@backstage/plugin-playlist-common": "0.1.13",
"@backstage/plugin-proxy-backend": "0.4.6",
"@backstage/plugin-puppetdb": "0.1.11",
"@backstage/plugin-rollbar": "0.4.28",
"@backstage/plugin-rollbar-backend": "0.1.53",
"@backstage/plugin-scaffolder": "1.17.0",
"@backstage/plugin-scaffolder-backend": "1.19.2",
"@backstage/plugin-scaffolder-backend-module-azure": "0.1.0",
"@backstage/plugin-scaffolder-backend-module-bitbucket": "0.1.0",
"@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.9",
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.32",
"@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.0",
"@backstage/plugin-scaffolder-backend-module-github": "0.1.0",
"@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.11",
"@backstage/plugin-scaffolder-backend-module-rails": "0.4.25",
"@backstage/plugin-scaffolder-backend-module-sentry": "0.1.16",
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.29",
"@backstage/plugin-scaffolder-common": "1.4.4",
"@backstage/plugin-scaffolder-node": "0.2.9",
"@backstage/plugin-scaffolder-react": "1.7.0",
"@backstage/plugin-search": "1.4.4",
"@backstage/plugin-search-backend": "1.4.8",
"@backstage/plugin-search-backend-module-catalog": "0.1.12",
"@backstage/plugin-search-backend-module-elasticsearch": "1.3.11",
"@backstage/plugin-search-backend-module-explore": "0.1.12",
"@backstage/plugin-search-backend-module-pg": "0.5.17",
"@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.1",
"@backstage/plugin-search-backend-module-techdocs": "0.1.12",
"@backstage/plugin-search-backend-node": "1.2.12",
"@backstage/plugin-search-common": "1.2.9",
"@backstage/plugin-search-react": "1.7.4",
"@backstage/plugin-sentry": "0.5.13",
"@backstage/plugin-shortcuts": "0.3.17",
"@backstage/plugin-sonarqube": "0.7.10",
"@backstage/plugin-sonarqube-backend": "0.2.10",
"@backstage/plugin-sonarqube-react": "0.1.11",
"@backstage/plugin-splunk-on-call": "0.4.17",
"@backstage/plugin-stack-overflow": "0.1.23",
"@backstage/plugin-stack-overflow-backend": "0.2.12",
"@backstage/plugin-stackstorm": "0.1.9",
"@backstage/plugin-tech-insights": "0.3.20",
"@backstage/plugin-tech-insights-backend": "0.5.22",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.40",
"@backstage/plugin-tech-insights-common": "0.2.12",
"@backstage/plugin-tech-insights-node": "0.4.14",
"@backstage/plugin-tech-radar": "0.6.11",
"@backstage/plugin-techdocs": "1.9.2",
"@backstage/plugin-techdocs-addons-test-utils": "1.0.25",
"@backstage/plugin-techdocs-backend": "1.9.1",
"@backstage/plugin-techdocs-module-addons-contrib": "1.1.3",
"@backstage/plugin-techdocs-node": "1.11.0",
"@backstage/plugin-techdocs-react": "1.1.14",
"@backstage/plugin-todo": "0.2.32",
"@backstage/plugin-todo-backend": "0.3.6",
"@backstage/plugin-user-settings": "0.7.14",
"@backstage/plugin-user-settings-backend": "0.2.7",
"@backstage/plugin-vault": "0.1.23",
"@backstage/plugin-vault-backend": "0.4.1",
"@backstage/plugin-vault-node": "0.1.1",
"@backstage/plugin-visualizer": "0.0.1",
"@backstage/plugin-xcmetrics": "0.2.46"
},
"changesets": [
"afraid-mice-give",
"brown-planes-sort",
"chilled-seahorses-clean",
"create-app-1703547661",
"curvy-dingos-jump",
"fast-tables-hammer",
"friendly-horses-kneel",
"funny-rings-fry",
"gold-pianos-worry",
"happy-forks-jam",
"large-poets-buy",
"lazy-teachers-walk",
"many-peaches-dress",
"new-plants-sort",
"orange-planets-suffer",
"renovate-126fde4",
"renovate-9647667",
"rotten-tools-clean",
"sour-taxis-rush",
"stale-hairs-sparkle"
]
}
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-github-issues': patch
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Updated dependency `octokit` to `^3.0.0`.
-11
View File
@@ -1,11 +0,0 @@
---
'@backstage/plugin-home-react': patch
'@backstage/plugin-home': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-scaffolder': patch
---
Updated dependency `@rjsf/utils` to `5.15.1`.
Updated dependency `@rjsf/core` to `5.15.1`.
Updated dependency `@rjsf/material-ui` to `5.15.1`.
Updated dependency `@rjsf/validator-ajv8` to `5.15.1`.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-scaffolder-backend-module-azure': patch
---
Updated dependency `azure-devops-node-api` to `^12.0.0`.
-145
View File
@@ -1,145 +0,0 @@
---
'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch
'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': patch
'@backstage/plugin-permission-backend-module-allow-all-policy': patch
'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch
'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch
'@backstage/plugin-catalog-backend-module-backstage-openapi': patch
'@backstage/plugin-auth-backend-module-atlassian-provider': patch
'@backstage/plugin-auth-backend-module-microsoft-provider': patch
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
'@backstage/plugin-auth-backend-module-pinniped-provider': patch
'@backstage/plugin-events-backend-module-bitbucket-cloud': patch
'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch
'@backstage/plugin-auth-backend-module-github-provider': patch
'@backstage/plugin-auth-backend-module-gitlab-provider': patch
'@backstage/plugin-auth-backend-module-google-provider': patch
'@backstage/plugin-auth-backend-module-oauth2-provider': patch
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
'@backstage/plugin-analytics-module-newrelic-browser': patch
'@backstage/plugin-auth-backend-module-okta-provider': patch
'@backstage/plugin-catalog-backend-module-bitbucket': patch
'@backstage/plugin-scaffolder-backend-module-yeoman': patch
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-catalog-backend-module-gerrit': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/plugin-events-backend-module-gerrit': patch
'@backstage/plugin-events-backend-module-github': patch
'@backstage/plugin-events-backend-module-gitlab': patch
'@backstage/plugin-events-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-aws': patch
'@backstage/plugin-github-pull-requests-board': patch
'@backstage/plugin-techdocs-addons-test-utils': patch
'@backstage/plugin-entity-feedback-backend': patch
'@backstage/backend-openapi-utils': patch
'@backstage/plugin-stack-overflow-backend': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-user-settings-backend': patch
'@backstage/frontend-plugin-api': patch
'@backstage/plugin-analytics-module-ga4': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-analytics-module-ga': patch
'@backstage/plugin-azure-sites-backend': patch
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-kubernetes-cluster': patch
'@backstage/plugin-microsoft-calendar': patch
'@backstage/plugin-newrelic-dashboard': patch
'@backstage/plugin-tech-insights-node': patch
'@backstage/plugin-entity-validation': patch
'@backstage/plugin-kubernetes-common': patch
'@backstage/plugin-airbrake-backend': patch
'@backstage/plugin-devtools-backend': patch
'@backstage/plugin-linguist-backend': patch
'@backstage/plugin-periskop-backend': patch
'@backstage/plugin-permission-react': patch
'@backstage/plugin-playlist-backend': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-apollo-explorer': patch
'@backstage/plugin-entity-feedback': patch
'@backstage/plugin-explore-backend': patch
'@backstage/plugin-gitops-profiles': patch
'@backstage/plugin-graphql-voyager': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-badges-backend': patch
'@backstage/plugin-bazaar-backend': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-octopus-deploy': patch
'@backstage/plugin-search-backend': patch
'@backstage/plugin-splunk-on-call': patch
'@backstage/plugin-stack-overflow': patch
'@backstage/plugin-techdocs-react': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-code-coverage': patch
'@backstage/plugin-config-schema': patch
'@backstage/plugin-cost-insights': patch
'@backstage/plugin-explore-react': patch
'@backstage/plugin-github-issues': patch
'@backstage/plugin-kafka-backend': patch
'@backstage/plugin-nomad-backend': patch
'@backstage/plugin-tech-insights': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-catalog-node': patch
'@backstage/plugin-code-climate': patch
'@backstage/plugin-gcp-projects': patch
'@backstage/plugin-todo-backend': patch
'@backstage/plugin-adr-backend': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-azure-sites': patch
'@backstage/plugin-firehydrant': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-home-react': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-lighthouse': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-stackstorm': patch
'@backstage/plugin-tech-radar': patch
'@backstage/plugin-codescene': patch
'@backstage/plugin-dynatrace': patch
'@backstage/plugin-gcalendar': patch
'@backstage/plugin-org-react': patch
'@backstage/plugin-pagerduty': patch
'@backstage/plugin-shortcuts': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-xcmetrics': patch
'@backstage/plugin-airbrake': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-devtools': patch
'@backstage/plugin-graphiql': patch
'@backstage/plugin-linguist': patch
'@backstage/plugin-newrelic': patch
'@backstage/plugin-opencost': patch
'@backstage/plugin-periskop': patch
'@backstage/plugin-playlist': patch
'@backstage/plugin-puppetdb': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-explore': patch
'@backstage/plugin-jenkins': patch
'@backstage/plugin-rollbar': patch
'@backstage/plugin-allure': patch
'@backstage/plugin-badges': patch
'@backstage/plugin-bazaar': patch
'@backstage/plugin-search': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-ilert': patch
'@backstage/plugin-kafka': patch
'@backstage/plugin-nomad': patch
'@backstage/plugin-vault': patch
'@backstage/plugin-gocd': patch
'@backstage/plugin-home': patch
'@backstage/plugin-todo': patch
'@backstage/plugin-adr': patch
'@backstage/plugin-org': patch
---
Remove some unused dependencies
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-components': patch
---
Removed unnecessary `history` and `immer` dependencies.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend-module-aws': patch
---
Added status and e-mail as labels to the AWS Account Resource
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-linguist': patch
---
Added alpha support for the New Frontend System (Declarative Integration)
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-devtools': patch
'@backstage/plugin-linguist': patch
---
Updated imports from named to default imports to help with the Material UI v4 to v5 migration
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/eslint-plugin': patch
---
Added new `@backstage/no-top-level-material-ui-4-imports` rule that forbids top level imports from Material UI v4 packages
+14 -7
View File
@@ -13,29 +13,33 @@ body:
required: true
attributes:
label: '📜 Description'
description: 'A clear and concise description of what the bug is. It bugs out when ...'
description: 'A clear and concise description of what the bug is.'
placeholder: 'It bugs out when ...'
- type: textarea
id: expected-behavior
validations:
required: true
attributes:
label: '👍 Expected behavior'
description: 'What did you think should happen? It should ...'
description: 'What did you think should happen?'
placeholder: 'It should ...'
- type: textarea
id: actual-behavior
validations:
required: true
attributes:
label: '👎 Actual Behavior with Screenshots'
description: 'What did actually happen? Add screenshots, if applicable. It actually ...'
description: 'What did actually happen? Add screenshots, if applicable.'
placeholder: 'It actually ...'
- type: textarea
id: steps-to-reproduce
validations:
required: true
attributes:
label: '👟 Reproduction steps'
description: 'How do you trigger this bug? Please walk us through it step by step. Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.'
placeholder: "\n
description: 'How do you trigger this bug? Please walk us through it step by step.'
placeholder:
"Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.\n
1. Go to '...'\n
2. Click on '....'\n
3. Scroll down to '....'"
@@ -45,14 +49,17 @@ body:
required: false
attributes:
label: '📃 Provide the context for the Bug.'
description: 'How has this issue affected you? What are you trying to accomplish? Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
description: 'How has this issue affected you? What are you trying to accomplish?'
placeholder: 'Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
- type: textarea
id: environment
validations:
required: false
attributes:
label: '🖥️ Your Environment'
description: 'Always provide output of `yarn backstage-cli info`; provide browser information when applicable. Include as many relevant details about the environment you experienced the bug in.'
description: 'Provide Browser Information
Provide Output of `yarn backstage-cli info`'
placeholder: 'Include as many relevant details about the environment you experienced the bug in.'
- type: checkboxes
id: no-duplicate-issues
attributes:
+4 -1
View File
@@ -14,6 +14,7 @@ body:
attributes:
label: '🔖 Feature description'
description: 'A clear and concise description of what the feature is.'
placeholder: 'You should add ...'
- type: textarea
id: context
validations:
@@ -21,11 +22,13 @@ body:
attributes:
label: '🎤 Context'
description: 'Please explain why this feature should be implemented and how it would be used. Add examples, if applicable.'
placeholder: 'In my use-case, ...'
- type: textarea
id: implementation
attributes:
label: '✌️ Possible Implementation'
description: 'A clear and concise description of what you want to happen. Not obligatory, but ideas as to the implementation of the addition or change.'
description: 'A clear and concise description of what you want to happen.'
placeholder: 'Not obligatory, but ideas as to the implementation of the addition or change'
- type: checkboxes
id: no-duplicate-issues
attributes:
+4 -1
View File
@@ -14,16 +14,19 @@ body:
attributes:
label: '🔖 Summary'
description: 'Provide a general summary of the plugin and how it should work'
placeholder: 'You should add ...'
- type: textarea
id: website
attributes:
label: '🌐 Project website (if applicable)'
description: 'Add a link to the open source project or product this plugin will integrate with, if existing'
placeholder: 'Website Link is ...'
- type: textarea
id: context
attributes:
label: '✌️ Context'
description: 'A clear and concise description about the Plugin and any additional context.'
description: 'A clear and concise description about the Plugin.'
placeholder: 'Providing additional context'
- type: checkboxes
id: no-duplicate-issues
attributes:
+8 -4
View File
@@ -13,24 +13,28 @@ body:
required: true
attributes:
label: '🔖 Need'
description: "Let us know why are you proposing this change. The problem we're trying to address and the benefits/impact we expect to get from this are ..."
description: 'Let us know why are you proposing this change'
placeholder: 'The problem were trying to address and the benefits/impact we expect to get from this are ...'
- type: textarea
id: proposal
validations:
required: true
attributes:
label: '🎉 Proposal'
description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback. Take special care in this section to describe any implications on data privacy or security.'
description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback.'
placeholder: 'Take special care in this section to describe any implications on data privacy or security.'
- type: textarea
id: alternatives
attributes:
label: '〽️ Alternatives'
description: 'What alternatives to the proposed solution were considered? What criteria/data was used to discard these?'
description: 'What alternatives to the proposed solution were considered?'
placeholder: 'What criteria/data was used to discard these?'
- type: textarea
id: risk
attributes:
label: '❌ Risks'
description: 'What other things happening could conflict or compete (for example for resources) with the proposal? What risk are there and how do we plan to handle them?'
description: 'What other things happening could conflict or compete (for example for resources) with the proposal?'
placeholder: 'What risk are there and how do we plan to handle them?'
- type: checkboxes
id: no-duplicate-issues
attributes:
+8 -5
View File
@@ -6,34 +6,37 @@ body:
- type: markdown
attributes:
value: |
We value your time and efforts to submit this UX Component form. 🙏
We value your time and efforts to submit this RFC form. 🙏
- type: textarea
id: ux-general
validations:
required: true
attributes:
label: '🔖 General'
description: |
'Write a nice note to the community requesting the creation of a new component. Include an image of your component. Bonus points for a GIF!'
description: 'Write a nice note to the community requesting the creation of a new component.'
placeholder: 'Include an image of your component. Bonus points for a GIF!'
- type: textarea
id: usage
validations:
required: true
attributes:
label: '💻 Usage'
description: "Tell us what's the point of this component/pattern is. How does it help? How should it work? Any rules?"
description: "Tell us what's the point of this component/pattern is."
placeholder: 'How does it help? How should it work? Any rules?'
- type: textarea
id: specs
validations:
required: true
attributes:
label: '📐 Specs'
description: "Include images that detail the redlines for your component. Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
description: 'Include images that detail the redlines for your component.'
placeholder: "Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
- type: textarea
id: future
attributes:
label: '🔮 Future'
description: 'List out any upcoming, exciting functionality for this component.'
placeholder: 'The component will have ...'
- type: checkboxes
id: no-duplicate-issues
attributes:
+31 -34
View File
@@ -12,16 +12,23 @@ jobs:
name: Cache Manifests File
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
# "If you specify the access for any of these scopes, all of those that are not specified are set to none."
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
actions: read # Access cache
outputs:
manifests-cache-key: ${{ env.MANIFESTS_FILE_HASH }}
git-ref: ${{ env.GIT_REF }}
pr-number: ${{ env.PR_NUMBER }}
action: ${{ env.ACTION }}
manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}
git-ref: ${{ steps.event.outputs.GIT_REF }}
pr-number: ${{ steps.event.outputs.PR_NUMBER }}
action: ${{ steps.event.outputs.ACTION }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1
with:
egress-policy: audit
disable-sudo: true
egress-policy: block
allowed-endpoints: >
api.github.com:443
- name: 'Download artifacts'
# Fetch output (zip archive) from the workflow run that triggered this workflow.
@@ -48,59 +55,50 @@ jobs:
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data));
- name: 'Unzip artifact'
run: unzip preview-spec.zip
- name: 'Accept event from first stage'
run: unzip preview-spec.zip event.json
- name: Read Event into ENV
id: event
run: |
echo 'EVENT_JSON<<EOF' >> $GITHUB_ENV
cat event.json >> $GITHUB_ENV
echo -e '\nEOF' >> $GITHUB_ENV
echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_OUTPUT
echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT
echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT
- name: Hash Rendered Manifests File
id: hash
# If the previous workflow was triggered by a PR close event, we will not have a manifests file artifact.
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
if: ${{ steps.event.outputs.ACTION != 'closed' }}
run: |
unzip preview-spec.zip manifests.rendered.yml
ls
echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV
echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT
- name: Cache Manifests File
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
if: ${{ steps.event.outputs.ACTION != 'closed' }}
uses: actions/cache@v3.3.2
with:
path: manifests.rendered.yml
key: ${{ env.MANIFESTS_FILE_HASH }}
- name: Read PR Number From Event Object
id: pr
run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV
- name: Read Event Type from Event Object
id: action
run: echo "ACTION=${{ fromJSON(env.EVENT_JSON).action }}" >> $GITHUB_ENV
- name: Read Git Ref From Event Object
id: ref
run: echo "GIT_REF=${{ fromJSON(env.EVENT_JSON).pull_request.head.sha }}" >> $GITHUB_ENV
key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}
- name: DEBUG - Print Job Outputs
if: ${{ runner.debug }}
run: |
echo "PR number: ${{ env.PR_NUMBER }}"
echo "Git Ref: ${{ env.GIT_REF }}"
echo "Manifests file hash: ${{ env.MANIFESTS_FILE_HASH }}"
echo "PR number: ${{ steps.event.outputs.PR_NUMBER }}"
echo "Git Ref: ${{ steps.event.outputs.GIT_REF }}"
echo "Action: ${{ steps.event.outputs.ACTION }}"
echo "Manifests file hash: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}"
cat event.json
deploy-uffizzi-preview:
permissions:
contents: read
pull-requests: write
id-token: write
name: Deploy to Uffizzi Virtual Cluster
needs:
- cache-manifests-file
if: ${{ github.event.workflow_run.conclusion == 'success' && needs.cache-manifests-file.outputs.action != 'closed' }}
permissions:
contents: read
pull-requests: write
id-token: write
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -142,7 +140,6 @@ jobs:
- name: Fetch cached Manifests File
id: cache
# if: ${{ contains(fromJSON('["create", "update"]'), env.UFFIZZI_ACTION) }}
uses: actions/cache@v3
with:
path: manifests.rendered.yml
@@ -30,5 +30,6 @@ jobs:
with:
# This also contains --config=.github/vale/config.ini ... :/
files: '${{ steps.generate.outputs.args }}'
version: 2.30.0 # TODO: migrate to v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
egress-policy: audit
- uses: actions/checkout@v4.1.1
- uses: actions/setup-python@v4.7.1
- uses: actions/setup-python@v4.8.0
with:
python-version: '3.9'
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: setup python
uses: actions/setup-python@v4.7.1
uses: actions/setup-python@v4.8.0
with:
python-version: '3.10'
+255
View File
@@ -0,0 +1,255 @@
---
title: Backstage Notifications System
status: provisional
authors:
- Rugvip
project-areas:
- core
creation-date: 2023-01-12
---
# BEP: Backstage Notifications System
[**Discussion Issue**](https://github.com/backstage/backstage/issues/22213)
- [Summary](#summary)
- [Motivation](#motivation)
- [Goals](#goals)
- [Non-Goals](#non-goals)
- [Proposal](#proposal)
- [Design Details](#design-details)
- [Release Plan](#release-plan)
- [Dependencies](#dependencies)
- [Alternatives](#alternatives)
## Summary
The Backstage Notifications System provides a way for Backstage plugins to send notifications to users. The notifications are displayed in the Backstage frontend UI, but future extensions can allow them to be sent via external channels such as email. The system includes a push mechanism to make sure that users receive notifications immediately, as well as persistence of notification history and read status.
## Motivation
Support for notifications is an old and common features request. See [#639](https://github.com/backstage/backstage/issues/639) and [#10652](https://github.com/backstage/backstage/issues/10652). There are also initiatives to implement notifications in [#20312](https://github.com/backstage/backstage/issues/20312) as well as the underlying infrastructure pieces, for example [#17997](https://github.com/backstage/backstage/issues/17997).
This proposal assumes that further motivation for a notifications system as a whole is not needed. The focus is instead on the specific goals of an initial notifications system, and generally aiming to address the need to coordinate this work.
### Goals
We aim to build a system that would provide support for the following type of notifications, as listed in [#10652](https://github.com/backstage/backstage/issues/10652):
- System-wide announcements or alerts
- Notifications for component owners (e.g. build failure, successful deployment, new vulnerabilities)
- Notifications for individuals (e.g. updates you have subscribed to, new required training courses)
- Notifications pertaining to a particular entity in the catalog (a given notification might apply to an entity and the owning team)
Initially we only target a single way to send notifications: via a REST API call to the notifications backend, which in turn also provides an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services).
The notifications system will need to support scaled deployments, where multiple backend instances may be deployed.
In the future we aim to provide an extensible system that can be customized to send notifications to users via other channels. Notifications can be captured and processed in-band in order to trigger custom behavior such as sending an email. The goal is for this to be possible to build, but not necessarily part of the initial implementation.
### Non-Goals
The following features are out of scope for this BEP:
- Building out specific support for channels such as email, Slack, and other external channels.
- Providing a fallback mechanisms when a notification cannot be delivered to a user. For example, if a user has not logged in for a long time, we will not attempt to send an email instead.
## Proposal
The notifications system is implemented through two net-new components, the `notifications` plugin, and the `signal` plugin.
The `notifications` plugin in its simplest form provides the following:
- A backend API for sending, reading, and interacting with notifications.
- Persistent storage of notification state.
- A frontend UI for viewing notifications.
The `signal` plugin provides the following:
- A backend API for pushing lightweight signals to online users.
- A connection between the frontend and backend that can be used to push messages to the client.
- A frontend API that lets plugins to subscribe to specific signals.
### Signals Plugin
In the backend the signal plugin implements a general purpose message bus for sending signals from backend plugins to connected users. It relies on the `EventBroker` from the [events plugin](https://github.com/backstage/backstage/blob/master/plugins/events-backend/README.md) for the actual message passing in the backend. In order to support scaled deployments, each signal backend instance has a separate subscription to the event broker so that each instance receives all events. It is then up to each backend instance to filter out events that are not relevant to it. For this reason, signals should be kept lightweight and not contain unnecessary data.
In the frontend the signal plugin has a persistent connection to the signal backend. This is initially implemented as a WebSocket connection, but could in the future also receive fallback mechanisms such as Server Sent Events or long polling. It is important that this connection is authenticated as we will be routing signals to specific users. The exact implementation of the authentication is not part of this proposal, but it should use whatever the outcome of the discussion in issue [#19581](https://github.com/backstage/backstage/issues/19581) is.
In order to route signals from the sender to the intended receiver the signal plugin uses the concept of signaling channels. They are just like the topics on the message bus, but we use separate terminology in order to avoid confusion. They also sit one layer beneath the even topic in the protocol stack, where the signal channel is communicated as part of the event payload. In the frontend, the signal plugin exposes an API to subscribe to a signal channel. Each time the user receives a signal on the specified channel, a listener is called with the signal payload.
### Notifications Plugin
The role of the notifications plugin is to manage the lifecycle of notifications. The backend plugin provides an API for other backends to send notifications, as well as an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services). It also provides a separate API for the frontend plugin to read notifications for an individual user and manage the read status of notifications.
The notification backend stores notification using the [database service](https://backstage.io/docs/backend-system/core-services/index#database). In particular it needs to store the following information for each notification:
- ID
- Payload
- Receivers
- Read status by user
The receivers is **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal.
The notification backend does not provide any new permissions, since creating notifications can only be done by other backend plugins, while reading notifications can only be done by the authenticated user. It is possible that we want to add a permissions for reading notifications, in particular for admin and impersonation use cases, but that is not part of this proposal or the initial implementation.
The notification frontend plugin provides a UI for viewing notifications, which in the initial implementation can be as simple as needed. The only requirement is that a user is able to view recent notifications and distinguish between read and unread notifications. A notification as marked as read once it has been interacted with. The frontend plugin also subscribes to the notifications signal channel and alerts the user when a new notification is received.
### Architecture Overview
The diagram below show an overview of the notifications system architecture and the interaction between the different components.
![notifications system architecture diagram](./notifications-architecture.drawio.svg)
The components that are presented with dashed lines are not directly part of this proposal, but included to be considered as future extensions.
Let's walk through the process of sending of a notification to a user:
1. A backend plugin that wants to send a notification to a user uses the `NotificationService`, which in turn makes a POST request to the notification backend. The request contains a filter to select the target users, as well as the notification payload.
1b. As the notification backend handles the request it could optionally invoke a series of notification processors. These processors can be used to transform the notification payload, send the notification through other channels, and decide whether the regular notification flow should continue or not. This step is not in scope for this proposal.
2. The notification backend stores the received notification in its database. At this point the notification is available from the notification backend's read API.
3. The notification backend published an event to the event bus on the `'signal'` topic. This event payload contains the signaling channel, in this case `'notifications'`, as well as the target user ID and the notification ID, but not the notification payload.
4. Each instance of the signal backend plugin subscribes to the `'signal'` topic and receives the event.
5. Each signal backend instance has a set of push channels set up to online users. The incoming event is filtered based on the target user ID and the signaling is pushed through all connections with a matching user ID.
6. The signal frontend plugin receives the signal and forwards it to all subscribers of the target channel. In this case, the notifications frontend plugin, who is subscribed to the `'notifications'` channel.
7. The notifications frontend plugin receives the signal with the notification ID. It then makes a request to the notification backend to fetch the notification payload and then displays the notification to the user.
7b. Rather than rendering the notification directly, the notifications frontend plugin leaves that to an extension installed by the frontend part of the backend plugin that sent the notification. This allows for a more customized notification experience which can also contain custom actions and data display. This step is not in scope for this proposal.
## Design Details
### Backend Services
The following backend service interfaces are added as part of this proposal.
#### `NotificationService`
```ts
// TODO - We may want to add an additional wrapping here with interfaces for Notification and NotificationParameters
interface SendNotificationRequest {
receivers: SignalReceivers;
/* TODO - please contribute :) */
}
interface SendNotificationResponse {
id: string;
receivers: SignalReceivers;
/* TODO - please contribute :) */
}
interface NotificationService {
sendNotification(
request: SendNotificationRequest,
): Promise<SendNotificationResponse>;
}
```
#### `SignalService`
```ts
type SignalReceivers =
| {
type: 'entity';
entityRef: string; // typically a user or group entity
}
| {
type: 'broadcast'; // all users
};
interface Signal {
channel: string;
receivers: SignalReceivers;
payload: JsonObject;
}
interface SignalService {
signal(signal: Signal): Promise<void>;
}
```
### Frontend API
The following frontend API is added as part of this proposal.
#### `SignalApi`
> TODO - we likely need a slightly different approach here, since APIs are lazy loaded.
```ts
interface SignalSubscriber {
unsubscribe(): void;
}
interface SignalApi {
subscribe(
channel: string,
listener: (payload: JsonObject) => void,
): SignalSubscriber;
}
```
> TODO: Add payload formats and API details
<!--
- A notification can be sent to any entity
- If the entity is an user, the notification is sent to that user
- If the entity is a group, the notification is sent to all users that are members of that group
- In other cases, the notification is sent to to the user or group in the `spec.owner` field
- Notification frontend shows users their own notifications in its own page and the number of unread notifications
in the main menu item
- Notifications can be set to `read` by the user and they are filtered out of the main view
- Notifications can be saved for later use by the user
- Each notification must have title, description and link
- Each notification can also have icon or image as an URL
- Notification frontend utilizes [Web Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification)
to notify user for new notifications
-->
## Release Plan
The notification and signal plugins are released as two new plugins in the Backstage ecosystem. They will both start out in an experimental state.
For the notification plugin to reach a stable release we much reach the following:
- A stable notifications payload format.
- A stable notifications receiver filter format.
- The event broker must have at least one implementation that supports scaled deployments.
For the signal plugin to reach a stable release we much reach the following:
- A stable signal receiver filter format.
- A stable signal channel API in the frontend.
If any changes are required to the frontend framework to facilitate the implementation of notifications or signals, these will be released as experimental alpha features. They will stay in alpha until they are deemed stable enough, which must happen before a stable release of the notifications system.
## Dependencies
Since the signal plugin relies on the event broker for communication, it is a dependency for the notifications system as a whole. The event broker does not currently implement any transport for scaled deployments, which is a requirement for scaled deployments of the notification system.
## Alternatives
### Signal Plugin Separation
One primary consideration for the notifications system was whether the notification plugin should set up its own frontend push connection rather than relying on the signal plugin. The signal plugin separation is done for three primary reasons:
1. The use-case of sending signals from backend plugins to frontend plugins is not limited to only notifications, since not all signals should necessarily be displayed directly to the user. For example, the catalog backend may want to send a signal to the frontend when an entity is updated so that users that are currently viewing the entity in the frontend can trigger an update of the view.
2. We want to limit the number of WebSocket connections that the frontend needs to maintain. By using a separated signal abstraction it is easier to extend the implementation to support other messaging patterns in the future. For example, we may want to move the Scaffolder logs to be sent via the signal plugin instead. That is much more straightforward with a separate signal plugin compared to adding it to the notifications plugin.
3. The technical implementation of sending signals is sufficiently complex that it makes sense to separate out to its own solution in order to reduce the complexity of the notifications plugin. In particular when it comes to handling scaled deployments.
### User-to-User Notifications
The notification backend API for sending notifications is only available to other backend plugins, and is not accessible to end users in the frontend. If this were to be added it would likely be a separate backend module that you can install alongside the notification backend. That is unless the permission framework can be extended to support default policy handlers so that we can reject the permission to send user notifications by default.
There are a few reasons we don't want to allow user-to-user notifications out of the box:
- To limit the possibility of spam. Even if well-intended, a notification overload can quickly lead to a bad user experience and users disabling and ignoring notifications.
- From a security perspective it's beneficial to avoid user sent notifications since they could be used to trick users into clicking on malicious links, or other similar attacks.
- Our assumption is that this is a feature that most adopters will not want to use, and so by having it be disabled by default we can avoid additional configuration steps.
@@ -0,0 +1,537 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="671px" height="311px" viewBox="-0.5 -0.5 671 311" content="&lt;mxfile scale=&quot;1&quot; border=&quot;20&quot;&gt;&lt;diagram id=&quot;2fh7CcgDxUdRYRy3FD-Z&quot; name=&quot;Page-1&quot;&gt;7Vxbk6I4FP41Vu0+tEVAUB9bu+192N3pWqdqZx4jREk1Agto6/76TSDckqhIA97W6RrJIdy+79xyEulp0/XuLYC+/YdnIaenKtaup730VHU40Mn/VLBPBCPDSASrAFuJCOSCOf4XMaHCpBtsobDUMfI8J8J+WWh6rovMqCSDQeB9lrstPad8VR+ukCCYm9ARpX9jK7ITqTZWcvlvCK9sdmXNYDsW0PxYBd7GZZfrqdos/iS71zA9Fesf2tDyPgsi7bWnTQPPi5Kt9W6KHIpsilpy3OzA3uy2A+RGVQ5IeQqjffroyCJIsKbrueRrYkdrh7QA2bRgaCOLNZaeGzHuCHHaJIxgED1T+PNjY9kMO/QEtA9yLa4HkRT373D0g273VZ01fxZ2veyKjT1riI/NkAi9TWCyB1OZHsFghVivwTCR0WcuHMewekPeGkXBnnQIkAMjvC1rB2RKtsr6ZYe+e5jciaowe3gCKgN6n+q5Uj5HclfssJwwslG4j1wU0yin1FDPpDRHfFgdcQJ0sE+O0tPmz/SEtJEfFrdKx72jAJMnQgETflGPFo5nfny3sVtSplhByebUc7wgxkFb6vRffLLA+0CFPUb8+YImpQ6gYU0ijwj3hQ4+VZDwiKKlHirVM97++f7G0f5kI7mDusrIkNpCZ8Oe+E8vwktsEgw8l+yZEIdJOBNUNvahsaOhZH/aOEJzH8YEfJKIU9bgQzRTvSrIk089+rcoiNDuKLOZrY84TAes/ZlHkhRnxS5EkYFyWBtKDuEI4Ok5zrf+oun39aPG35q9lqNLO8aricY7atp2K7M1qu2rq7vqW/OuEoLUSxGknfJfs4Cge+cOLAtunTgwAfE5XrnQuctYoVeIFEpLQKdG1arvOZXtl3xR0dMUHVKLvkYXfc3gUr4mdTYtE1I3bz9OZHf8AL1pgmpl2pldpk7yRKYNxkf7fz3THvyvPVW0x7hJ7eEjRePaM66rPWcMGzLtAUXdKajSAe259oRVombapYKIfjh9usNUlbcKWaLaVv5U12JAHYtRzrOY8xW9kv1UsgZDtIaLDd8MwRrenc0K04Hbj7scUDxpfEGvy+LT6Djc1+aAStWmNsDvdOAMzh7PXZdzqeMfKzkkSbUeNB6fD8378BoBOKaTGxXmfcQzqVzGmJ35xAzSuZmpKr/MwcS03H3UbFoKhjWDbHlQA44q0aFBjXLCDi6ZcgJJkfRihQvQTBX7MVi60vLFqYlCvnzR9EQhqD0AfUQdus4ixikdEsrdTeuQOFvzukXxHUwoB8G1JJ4N5JpcXiFJNEdt5ZliieGOcAXD0+OnQVvIisPVO0JW1S6HbJqlFpDt9/sCuORJojKCZURYFCrCykTQwSsSEl5Mgg9d1jShuGATOs9sxxpbFr2MlLIyqU1ocYWJxbbGodndPgjW2ZDuAlhrqoC1v1k4OLRpdpDEvqvEnV+T0gAPwlI2CQ+ymKg2wYO4amEReNAyYfhADGSI84tcu2BAkpVoM/b3OAxw5RhVwoDeFgNi9hKiYEuzbsXfUI/0MCzwk7uayMKwLRbGAgvv3+bfHwf8J5X3QpI4YLSE/uDcRRhN/pyi89JE+uuJUhGSZSTtV9a5gtSIo+9AYb1GWSF9pGJZYUdUP5lVn+/DCK0F2u9mSosbSXS6FFSs56A1xKTLLHSg+UG+IwTXYU+dUo2LzGsdZbTh5nhiqs7zNuLmxFD/F/E4kgLb/eLPhxmZZbQWZoYC/j3VcCjSoQ/dEgXGPxv6Y8KJmcD7TF3vavGLDhKryb9/jYFRKFZPYQwW7QtUfxfvSM9Dtlb0+z3wTBSG5JzsytQq44sn+8VA6DjYDw8RVjUmXlVJSwhCHZZhB2Ki9/b6SHmeMNYBIvhaSwaY+t4C+ECAvrLCw9BPfsO8xDsK2UmlXy5V05Qpt2UsDL0p5RYKtkMR4LYijC4WESWr428cYL5I2yW+Yk4LFncHsPBLTImLaA1hsSQoGRzeNsD8XFmX8Ir1PsmrDG4bXsDPLIw7xFdM8Y17w5dPILqEV8zgh/fnf/mpsU4RFvNjyWLCGweYn+eVVZrbAjgd6xxbrRDa0Keb5t7BtD6gnUZ6kQwcfl9kguyVOt82ETkNYvJkjPoy6I8NNf8bXP+gkUtKdJEy2TIIvQnKxIKayNnN2wTgXrXTYVZiiEnf1IauG78cawodZxGXLW9ojC4AL6Gn8pS8tHoMmuGCNPPXZiVV/vzNZNrrfw==&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<defs/>
<g>
<path d="M 230 120 L 230 80" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
<path d="M 290 120 L 290 110 Q 290 100 300 100 L 310 100 Q 320 100 320 94.06 L 320 88.12" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 320 81.12 L 322.33 88.12 L 317.67 88.12 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="200" y="120" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 140px; margin-left: 201px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Notification Backend
</div>
</div>
</div>
</foreignObject>
<text x="260" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Notification Backend
</text>
</switch>
</g>
<path d="M 200 260 L 148.12 260" fill="none" stroke="#666666" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
<path d="M 141.12 260 L 148.12 257.67 L 148.12 262.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 260 240 L 260 168.12" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 260 161.12 L 262.33 168.12 L 257.67 168.12 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="200" y="240" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 260px; margin-left: 201px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Notification Frontend
</div>
</div>
</div>
</foreignObject>
<text x="260" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Notification Frontend
</text>
</switch>
</g>
<rect x="430" y="120" width="100" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 140px; margin-left: 431px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Signal Backend
</div>
</div>
</div>
</foreignObject>
<text x="480" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Signal Backend
</text>
</switch>
</g>
<path d="M 480 231.88 L 480 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 480 238.88 L 477.67 231.88 L 482.33 231.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 480 240 L 480 210 Q 480 200 490 200 L 560 200 Q 570 200 570 190 L 570 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 480 240 L 480 210 Q 480 200 490 200 L 620 200 Q 630 200 630 190 L 630 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 430 260 L 328.12 260" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 321.12 260 L 328.12 257.67 L 328.12 262.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="430" y="240" width="100" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 260px; margin-left: 431px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Signal Frontend
</div>
</div>
</div>
</foreignObject>
<text x="480" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Signal Frontend
</text>
</switch>
</g>
<path d="M 140 140 L 191.88 140" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 198.88 140 L 191.88 142.33 L 191.88 137.67 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="20" y="120" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 140px; margin-left: 21px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Plugin X Backend
</div>
</div>
</div>
</foreignObject>
<text x="80" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Plugin X Backend
</text>
</switch>
</g>
<rect x="20" y="240" width="120" height="40" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 260px; margin-left: 21px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Plugin X Frontend
</div>
</div>
</div>
</foreignObject>
<text x="80" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Plugin X Frontend
</text>
</switch>
</g>
<path d="M 320 140 L 390 140 Q 400 140 400 130 L 400 70 Q 400 60 410 60 L 431.88 60" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 438.88 60 L 431.88 62.33 L 431.88 57.67 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 480 80 L 480 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 480 118.88 L 477.67 111.88 L 482.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 480 80 L 480 90 Q 480 100 490 100 L 560 100 Q 570 100 570 105.94 L 570 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 570 118.88 L 567.67 111.88 L 572.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 480 80 L 480 90 Q 480 100 490 100 L 620 100 Q 630 100 630 105.94 L 630 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 630 118.88 L 627.67 111.88 L 632.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="440" y="40" width="80" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 60px; margin-left: 441px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Event Broker
</div>
</div>
</div>
</foreignObject>
<text x="480" y="64" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Event Broker
</text>
</switch>
</g>
<rect x="550" y="120" width="40" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<rect x="610" y="120" width="40" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
<rect x="530" y="120" width="20" height="40" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 140px; margin-left: 531px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
...
</div>
</div>
</div>
</foreignObject>
<text x="540" y="144" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
...
</text>
</switch>
</g>
<rect x="590" y="120" width="20" height="40" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 140px; margin-left: 591px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
...
</div>
</div>
</div>
</foreignObject>
<text x="600" y="144" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
...
</text>
</switch>
</g>
<rect x="320" y="120" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 130px; margin-left: 321px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
publish event
</div>
</div>
</div>
</foreignObject>
<text x="360" y="133" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
publish event
</text>
</switch>
</g>
<rect x="520" y="80" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 90px; margin-left: 521px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
broadcast
</div>
</div>
</div>
</foreignObject>
<text x="560" y="93" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
broadcast
</text>
</switch>
</g>
<rect x="500" y="180" width="50" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 190px; margin-left: 501px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
???
</div>
</div>
</div>
</foreignObject>
<text x="525" y="193" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
???
</text>
</switch>
</g>
<rect x="480" y="210" width="70" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 220px; margin-left: 481px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
server push
</div>
</div>
</div>
</foreignObject>
<text x="515" y="223" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
server push
</text>
</switch>
</g>
<rect x="140" y="120" width="60" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 130px; margin-left: 141px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
POST
</div>
</div>
</div>
</foreignObject>
<text x="170" y="133" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
POST
</text>
</switch>
</g>
<path d="M 190 60 L 158.12 60" fill="none" stroke="#666666" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
<path d="M 151.12 60 L 158.12 57.67 L 158.12 62.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<rect x="30" y="40" width="120" height="40" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 31px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
External System
</div>
</div>
</div>
</foreignObject>
<text x="90" y="64" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
External System
</text>
</switch>
</g>
<rect x="30" y="20" width="120" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 30px; margin-left: 31px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
email/slack/teams, etc.
</div>
</div>
</div>
</foreignObject>
<text x="90" y="33" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
email/slack/teams, etc.
</text>
</switch>
</g>
<rect x="140" y="240" width="60" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 250px; margin-left: 141px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Render
</div>
</div>
</div>
</foreignObject>
<text x="170" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
Render
</text>
</switch>
</g>
<ellipse cx="230" cy="60" rx="40" ry="20" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 60px; margin-left: 191px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="color: rgb(51, 51, 51); font-size: 12px;">
Processor
</span>
</div>
</div>
</div>
</foreignObject>
<text x="230" y="63" fill="#333333" font-family="Helvetica" font-size="10px" text-anchor="middle">
Processor
</text>
</switch>
</g>
<rect x="260" y="190" width="30" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 200px; margin-left: 261px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
GET
</div>
</div>
</div>
</foreignObject>
<text x="275" y="203" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
GET
</text>
</switch>
</g>
<ellipse cx="160" cy="160" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 160px; margin-left: 151px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
1
</div>
</div>
</div>
</foreignObject>
<text x="160" y="163" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
1
</text>
</switch>
</g>
<ellipse cx="340" cy="160" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 160px; margin-left: 331px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
3
</div>
</div>
</div>
</foreignObject>
<text x="340" y="163" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
3
</text>
</switch>
</g>
<ellipse cx="210" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 201px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
1b
</div>
</div>
</div>
</foreignObject>
<text x="210" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
1b
</text>
</switch>
</g>
<ellipse cx="460" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 451px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
4
</div>
</div>
</div>
</foreignObject>
<text x="460" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
4
</text>
</switch>
</g>
<ellipse cx="500" cy="180" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 180px; margin-left: 491px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
5
</div>
</div>
</div>
</foreignObject>
<text x="500" y="183" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
5
</text>
</switch>
</g>
<ellipse cx="410" cy="280" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 280px; margin-left: 401px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
6
</div>
</div>
</div>
</foreignObject>
<text x="410" y="283" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
6
</text>
</switch>
</g>
<ellipse cx="180" cy="280" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 280px; margin-left: 171px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
7b
</div>
</div>
</div>
</foreignObject>
<text x="180" y="283" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
7b
</text>
</switch>
</g>
<ellipse cx="240" cy="220" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 220px; margin-left: 231px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
7
</div>
</div>
</div>
</foreignObject>
<text x="240" y="223" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
7
</text>
</switch>
</g>
<path d="M 300 34.96 C 300 32.22 308.95 30 320 30 C 325.3 30 330.39 30.52 334.14 31.45 C 337.89 32.38 340 33.65 340 34.96 L 340 75.04 C 340 76.35 337.89 77.62 334.14 78.55 C 330.39 79.48 325.3 80 320 80 C 314.7 80 309.61 79.48 305.86 78.55 C 302.11 77.62 300 76.35 300 75.04 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 340 34.96 C 340 36.28 337.89 37.54 334.14 38.47 C 330.39 39.4 325.3 39.93 320 39.93 C 314.7 39.93 309.61 39.4 305.86 38.47 C 302.11 37.54 300 36.28 300 34.96" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
<ellipse cx="275" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 266px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
2
</div>
</div>
</div>
</foreignObject>
<text x="275" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
2
</text>
</switch>
</g>
<rect x="320" y="240" width="110" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 250px; margin-left: 321px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Channel Callback
</div>
</div>
</div>
</foreignObject>
<text x="375" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
Channel Callback
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 44 KiB

+99
View File
@@ -0,0 +1,99 @@
---
title: BEP Title
status: provisional
authors:
- '@ghost'
owners:
project-areas:
- aaa
- bbb
creation-date: yyyy-mm-dd
---
<!--
**Note:** When your BEP is complete, all these pre-existing comments should be removed
When editing BEPs, aim for tightly-scoped, single-topic PRs to keep discussions focused. If you disagree with what is already in a document, open a new PR with suggested changes.
-->
# BEP: <!-- Your short, descriptive title -->
<!-- Before merging the initial BEP PR, create a feature issue and update the below link. You can wait with this step until the BEP is ready to be merged. -->
[**Discussion Issue**](https://github.com/backstage/backstage/issues/NNNNN)
- [Summary](#summary)
- [Motivation](#motivation)
- [Goals](#goals)
- [Non-Goals](#non-goals)
- [Proposal](#proposal)
- [Design Details](#design-details)
- [Release Plan](#release-plan)
- [Dependencies](#dependencies)
- [Alternatives](#alternatives)
## Summary
<!--
The summary of the BEP is a few paragraphs long and give a high-level overview of the features to be implemented. It should be possible to read *only* the summary and understand what the BEP is proposing to accomplish and what impact it has for users.
-->
## Motivation
<!--
This section is for explicitly listing the motivation, goals, and non-goals of
this BEP. Describe why the change is important and the benefits to users.
-->
### Goals
<!--
List the specific goals of the BEP. What is it trying to achieve? How will we
know that this has succeeded?
-->
### Non-Goals
<!--
What is out of scope for this BEP? Listing non-goals helps to focus discussion
and make progress.
-->
## Proposal
<!--
This is where we get down to the specifics of what the proposal actually is.
This should have enough detail that reviewers can understand exactly what
you're proposing, but should not include things like API designs or
implementation.
-->
## Design Details
<!--
This section should contain enough information that the specifics of your
change are understandable. This may include API specs or even code snippets.
If there's any ambiguity about HOW your proposal will be implemented, this is the place to discuss them.
-->
## Release Plan
<!--
This section should describe the rollout process for any new features. It must take our version policies into account and plan for a phased rollout if this change affects any existing stable APIs.
If there is any particular feedback to be gathered during the rollout, this should be described here as well.
-->
## Dependencies
<!--
List any dependencies that this work has on other BEPs or features.
-->
## Alternatives
<!--
What other approaches did you consider, and why did you rule them out? These do
not need to be as detailed as the proposal, but should include enough
information to express the idea and why it was not acceptable.
-->
+86
View File
@@ -0,0 +1,86 @@
# Backstage Enhancement Proposals (BEPs)
A Backstage Enhancement Proposal (BEP) is a way to propose, communicate and coordinate on new efforts for the Backstage project.
## Quick start for the BEP process
1. Discuss the idea with the community and maintainers. Either here on GitHub, Discord, or during community sessions or SIG meetings.
Make sure that others think the work is worth taking up and will help review the BEP and any code changes required.
1. Make a copy of the [BEP template](./NNNN-template/) directory as `beps/NNNN-short-descriptive-title`, where `NNNN` is the next available number padded with leading zeroes.
1. Fill out as much of the YAML metadata as you can.
1. Fill out the template as best you can.
1. If you want the BEP to be owned by a particular project area, add an entry for the BEP folder to [CODEOWNERS](../.github/CODEOWNERS).
1. Create a PR for the BEP. Title it "BEP: &lt;title&gt;". Aim to get the high level goals clarified and avoid getting hung up on specific details. The PR can be merged early and iterated on.
1. Once the BEP is ready to be merged, create a [feature issue](https://github.com/backstage/backstage/issues/new?template=feature.yaml) titled "BEP: &lt;title&gt;". Use the summary of the BEP as description and link to the BEP PR in the context section. Once the PR is merged, the issue should be updated to link to the BEP folder instead. This issue will serve as a general discussion issue for the BEP.
1. Once the initial BEP is merged you should keep iterating on it until it is ready to leave that `provisional` state. Leaving the `provisional` state is a decision made by the project area maintainers.
Just because a BEP is merged does not mean it is complete or approved for implementation. Any BEP marked as `provisional` is a working document and subject to change.
The authors of the BEP are also responsible for driving the BEP forward all the way to implementation. The approval of a BEP is not a commitment to implement it.
## FAQs
### Do I have to use the BEP process?
No, but it is recommended for larger changes and contributions that affect the Backstage framework or core features where you want to make design decisions upfront and iterate on them across several PRs.
### What is the difference between a BEP and an RFC issue?
An RFC issue is a good way to receive feedback on an idea. The BEP process may involve getting feedback on an idea, but it takes things further by making it easier to iterate on the design of a new feature, getting it approved by the owning project area maintainers, and tracking its implementation.
While anyone can open an RFC issue, the features added by a BEP need to be approved by the owners before it can be merged. The BEP will also contain the latest agreed upon design, whereas an RFC issue is more of a discussion forum.
Often a BEP can start out as an RFC issue, which may then be converted into a BEP once the idea has received an owner and been approved.
### Should I use the BEP process for new or existing Backstage plugins?
No, except for plugins that implement core features of Backstage. The BEP process is only intended for changes to the Backstage framework and core features.
### Can I update an existing BEP?
Yes! As long as the BEP is still in the `provisional` state you should keep iterating on it. Please keep each PR focused on a single topic and avoid long-running and overly broad PRs.
### Can I update a BEP that was submitted by someone else?
Yes! BEPs are living documents and anyone can suggest changes to them. We encourage to challenge the design decisions in a BEP and suggest alternatives. You can also help fill out details in a BEP that has not yet been fully fleshed out.
### What's the difference between a BEP and an [ADR](https://backstage.io/docs/architecture-decisions/)?
Architecture Decision Records (ADRs) are used to document decisions made for development within the Backstage project. They are not intended to be used for proposing new features or changes to Backstage.
### My FAQ isn't answered here!
The BEP process is still evolving!
If something is missing or not answered here feel free to reach out on our community [Discord](https://discord.gg/backstage-687207715902193673).
If you want to propose a change to the BEP process you can also open a PR directly with your proposal.
### BEP Metadata
At the start of each BEP is a YAML document that contains metadata about the BEP. These are the fields that should currently be provided:
| Field | Description |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **title** | The title of the BEP in plain language. The title will also be used in the BEP filename. See the template for instructions and details. |
| **status** | The current state of the BEP, must be one of the values listed in the [BEP Status](#bep-status) section. |
| **authors** | A list of GitHub IDs for the authors of the BEP. Typically only the original authors are included, but additional authors can be added if significant contributions are made. |
| **owners** | A list of GitHub IDs for the owners of the BEP. The owners are responsible for the implementation of the BEP, and are required for the BEP to move to the `implementable` status. |
| **project-areas** | The Project Areas closely associated with this BEP that need to approve it. For a list of existing project areas, see [OWNERS.md](../OWNERS.md). If the BEP is not related to any existing project area, use `core-maintainers` instead. |
| **creation-date** | The `yyyy-mm-dd` date that the BEP was first submitted in a PR. |
## BEP Status
The BEP Status is critical to clearly communicate the status of each BEP. Each BEP must have its status field set to one of the following values:
- `provisional`: The BEP has been proposed and is actively being defined. The BEP as been approved by the owning project area maintainers as work to be done.
- `implementable`: The approvers have approved this BEP for implementation.
- `implemented`: The BEP has been implemented and is no longer actively changed.
- `deferred`: The BEP is proposed but not actively being worked on.
- `rejected`: The approvers and authors have decided that this BEP is not moving forward.
The BEP is kept around as a historical document.
- `withdrawn`: The authors have withdrawn the BEP.
- `replaced`: The BEP has been replaced by a new BEP.
### Prior Art
The BEP process is heavily inspired by the [Kubernetes Enhancement Proposal (KEP) process](https://github.com/kubernetes/enhancements/blob/master/keps/README.md).
@@ -0,0 +1,429 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="897px" height="646px" viewBox="-0.5 -0.5 897 646" content="&lt;mxfile scale=&quot;1.5&quot; border=&quot;20&quot;&gt;&lt;diagram id=&quot;gKBvn7eBFHudv9VMIRD-&quot; name=&quot;Page-1&quot;&gt;7V1tb6M4EP41kXZPahVwIPCxabe3J3V11fWku/3oECdBS3HOkG2zv/5ssHkzJIQQ0xCyUjcM2JiZeWbG4zEZgfvX998J3Ky/4QXyRvp48T4CDyNdN0xA/zLCLibYUzMmrIi7iElaSnhxfyFOHHPq1l2gIHdhiLEXups80cG+j5wwR4OE4Lf8ZUvs5e+6gSskEV4c6MnUf9xFuI6pYDJO6V+Ru1qLO1v8xBw6P1YEb31+u5EOltEnPv0KRVf8+mANF/gtQwJfRuCeYBzG317f75HHOCu4Frd7rDibDJsgP6zTwOAtfkJvi8SQo4GFO8GL6HEQazAegdnb2g3RywY67OwbFT6lrcNXjx5p9OvS9bx77GEStQVLg/2j9CAk+AfKnDGjD2uB/TBDjz+UzgeGSIjeK59OS3hGNRHhVxSSHb1ENNCNuAnXwhshv7dUptqY09YZeYrrIFejVdJ1ykv6hbOzgrV6r1mrdcjaid1n1t4I49CJ1o57zVrQIWsnVq9Zq5ld8nbab95Ou+TtWGIlWtBoiR/62Ed53qF3N/yXsflWN/jhd8519v3hPXuwEwc+HVbcyhCH30WH7CBtFh2l7RZ3LOCjh3MPOz/+Xrt+TH50PTGiIIQk5FHmJD6bOTpe1jFDGBf2S5QyDW+Jw6/iKknHskL8KlAheII8GLo/892fJEStsRCPkeFFy0JXJQvZNtWVxXQA1AEhThUJUY7uZ3TuR/lAiQ9o4+HdKxu6Pr77WI6ohKWSb9rjiKwuHZHE8kdCnzXm+d1m0ydGFwJVzZD5bJ2JzSWqfay9OqfpyZuaoiHKi5wx3HWgd+e5K9rTw6u7WHjRYDFxf1HxwUT69IB3Yzf0fk2t3gEjN5GNnEhrFOzlCVaPN33GbmSzxCV4uQzoTTPKk17DNRUUNLWogfGj8EZ7+ilMerViP/HzS/1Eypw8cT39tveqMybhGq+wD70vKfWSw1tnS35GiGhm5Rq6ZqNEbRW5ZsOQDNhddAEO14iwQRG4XLpOqRo8wTny8gKH3Ho49IFp+z1mhaDA/QXnUX9MehumrtGTGLOR8bBvNsgz2bzxKMFDls+x5lY7jfGtZml8JtwU+omnz+f39AIcZcvQAIlg/8zyCCReRlz8cZBoqoKiHLPRJnDjsh6msxA56wV2gpF+HzgUk9hbUIBN6WWPv10cOsG4nKm8J+ourCnIgepGawerZt512meAqi7b1E93W2pPfcbr0PVXn+nZvxDlXYDot2eC33eSCC84BTfJxyeWynmPsddMDgm42qbQlE0hMBSZwonZWIqX4d06laIqhyZufjjvc98j65eYtk7SPmAwf+0AZ1oCHKDK/E0G83c+KU5UmT95nbXC/M16ZP6KwZ9S82fujxvKJ8m5meb1rOoBUSuYwYapChvi5hlswI+2KHFqYVIBB4nSZ4AwKcEBaAMH0wEHtXGgyzgwLFU40GUcbKl29AgIyXJcJ0Bosn5xrUAAJQ6hIk/XPhCABAQHhtDDqz5hoQ4UjDNBYdpkAeFaoVCykGyqKj8D8jpAgCBx+uQVimXbSoGwv7xvAEIWCCULYqauCgjyOkq6CNYbKNg1oGCeCwr6AIXaUChJpZuqMoJATqVnFoH7AwapeF8lGkxrQENtNJRkVo2Kkpv20SBnVjd9W0OXlpFUTpuBvP3q2duuXF92vMEabthXigNvNyMswR0e5nUqGHbksUqVZxy4oYtZFYqHlqwPUZzyVDidFKmIchYSP311NcsCBuvkbm1IRy9ujtM0WTqgRDpGG9KpsaVzEEtuwn1AKmYLUjFkF93AnVx9ZfjHqfs7dXdMoQDtiDrxYn23VVDPpnXiRdfQXp24UbanNK1dTFJ59zyTcaFli0ZF6UxStjixRMZ5l+u8faVpICS78/iWHjwj4tIxMzGeWIVAj+TOLiaANizZ5Fiqll+NGtvrkwhi57nUGRBwOHyYx27jaZ4Qkle8/LkNaTdIiIDz+9aYahPd4n+tffyvirUPyeXEKLxYzaCJDROZiEI/UxRud754NeA1xavdJV6PifivGa9SMlUhXJMJ+oDXD4BXMaXL4VXVhndx8wGvh7ZuF96MpRavnS8EDnhN8VpSjqgOr3I54oDXErx2C9cm+bQBrmeCqy7D1VZVLCZuPsD1wGqq1mk4vH8vUld4vRyInVpcUJ4Ult49KKWX20sLm3JV5wDUMqB2OW+1O980M/jVFPQllafK0kxm2RsoBriWpIW7xKspl0VWS+m6l/8TX3dg/b+NvYfTMl9neowDwQb6OfmY/23ZW+tnuW8r9v/XZEndY08WvWZ/IfqhQ4i7iq8V5Dkp7XyOCcXnjRNj4C4aGvl0c5Olfy4dRINxp/tZg8rRFnSUCjrM618etHybcxb5nFRbw8r0PV/b0IbageIiEZCNQRKKt17CK9vsJ7xi3KDEBxjCOQyQXLbVX+aXmeKzcd+uEeAyT7epfNQ6ZQfHLlLq43reSJS9nMIBa4gZwqwuyGISlSCyKyqTidaGTI6JEK5ZJvVg0opIalQHXrdIFAjBrmGrzmatOzHONX7q4Uq0rmIO3YFxHmqv6slEoXEeymsOiESFca4RtJw7lJbeVaHSWIuc0qCFdsV7JtUba3soDKgnE3XG2tYHkewXiQIhaONjpv3XnYTWNf1Whse50tDaWPajD7NvL5Tyhx+E0HeuKhuoj6clzG8rHzhiv6ojfn82Xh9Pf+IXfPkf&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<defs/>
<g>
<rect x="717" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="702" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="499.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="484.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="289.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="274.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<path d="M 297 279 L 265.37 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 260.57 235.29 L 267.3 239.45 L 263.45 242.65 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 334.5 279 L 334.5 243.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 235.68 L 337 243.18 L 332 243.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 372 279 L 403.63 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 408.43 235.29 L 405.55 242.65 L 401.7 239.45 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="259.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 174px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Backend Deployment A
</div>
</div>
</div>
</foreignObject>
<text x="223" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Backend Deployme...
</text>
</switch>
</g>
<rect x="484.5" y="564" width="120" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 396px; margin-left: 324px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Frontend App
</div>
</div>
</div>
</foreignObject>
<text x="363" y="400" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Frontend App
</text>
</switch>
</g>
<path d="M 544.5 564 L 544.5 528.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 544.5 520.68 L 547 528.18 L 542 528.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 507 459 Q 507 399 420.75 399 Q 334.5 399 334.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 340.68 L 337 348.18 L 332 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 286px; margin-left: 284px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
All other traffic
</div>
</div>
</div>
</foreignObject>
<text x="284" y="290" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
All other traffic
</text>
</switch>
</g>
<path d="M 582 459 Q 582 399 668.25 399 Q 754.5 399 754.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 754.5 340.68 L 757 348.18 L 752 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 286px; margin-left: 468px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
/api/{techdocs,scaffolder}/*
</div>
</div>
</div>
</foreignObject>
<text x="468" y="290" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
/api/{techdocs,scaffolder}/*
</text>
</switch>
</g>
<rect x="469.5" y="459" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 326px; margin-left: 314px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
(Authenticating) Reverse Proxy
</div>
</div>
</div>
</foreignObject>
<text x="363" y="330" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
(Authenticating)...
</text>
</switch>
</g>
<path d="M 717 279 L 711.01 243.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 709.78 235.65 L 713.47 242.64 L 708.54 243.46 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 792 279 L 823.63 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 828.43 235.29 L 825.55 242.65 L 821.7 239.45 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="679.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 454px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Backend Deployment C
</div>
</div>
</div>
</foreignObject>
<text x="503" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Backend Deployme...
</text>
</switch>
</g>
<path d="M 507 279 L 494.9 242.71" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 492.53 235.59 L 497.27 241.92 L 492.53 243.5 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 582 279 L 594.1 242.71" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 596.47 235.59 L 596.47 243.5 L 591.73 241.92 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="469.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 314px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Backend Deployment B
</div>
</div>
</div>
</foreignObject>
<text x="363" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Backend Deployme...
</text>
</switch>
</g>
<path d="M 259.5 189 Q 259.5 189 259.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 259.5 153.18 L 262 160.68 L 257 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="229.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 154px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
app
</div>
</div>
</div>
</foreignObject>
<text x="173" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
app
</text>
</switch>
</g>
<path d="M 334.5 189 Q 334.5 189 334.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 153.18 L 337 160.68 L 332 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="304.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 204px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
auth
</div>
</div>
</div>
</foreignObject>
<text x="223" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
auth
</text>
</switch>
</g>
<path d="M 492 189 Q 492 189 492 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 492 153.18 L 494.5 160.68 L 489.5 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="454.5" y="189" width="75" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 141px; margin-left: 304px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
catalog
</div>
</div>
</div>
</foreignObject>
<text x="328" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
catalog
</text>
</switch>
</g>
<path d="M 597 189 Q 597 189 597 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 597 153.18 L 599.5 160.68 L 594.5 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="559.5" y="189" width="75" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 141px; margin-left: 374px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
search
</div>
</div>
</div>
</foreignObject>
<text x="398" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
search
</text>
</switch>
</g>
<path d="M 709.5 189 Q 709.5 189 709.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 709.5 153.18 L 712 160.68 L 707 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="664.5" y="189" width="90" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 141px; margin-left: 444px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
techdocs
</div>
</div>
</div>
</foreignObject>
<text x="473" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
techdocs
</text>
</switch>
</g>
<path d="M 829.5 189 Q 829.5 189 829.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 829.5 153.18 L 832 160.68 L 827 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="784.5" y="189" width="90" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 141px; margin-left: 524px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
scaffolder
</div>
</div>
</div>
</foreignObject>
<text x="553" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
scaffolder
</text>
</switch>
</g>
<path d="M 409.5 189 Q 409.5 189 409.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 409.5 153.18 L 412 160.68 L 407 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="379.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 254px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
proxy
</div>
</div>
</div>
</foreignObject>
<text x="273" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
proxy
</text>
</switch>
</g>
<path d="M 229.5 174 L 218.25 174 Q 207 174 207 189 L 207 200.25 Q 207 211.5 195.75 211.5 L 190.13 211.5 Q 184.5 211.5 195.75 211.5 L 201.38 211.5 Q 207 211.5 207 226.5 L 207 237.75 Q 207 249 218.25 249 L 229.5 249" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 32px; height: 1px; padding-top: 141px; margin-left: 89px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Plugins
</div>
</div>
</div>
</foreignObject>
<text x="121" y="145" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
Plugi...
</text>
</switch>
</g>
<path d="M 229.5 264 L 218.25 264 Q 207 264 207 279 L 207 294 Q 207 309 195.75 309 L 190.13 309 Q 184.5 309 195.75 309 L 201.38 309 Q 207 309 207 324 L 207 339 Q 207 354 218.25 354 L 229.5 354" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
<path d="M 544.5 459 Q 544.5 459 544.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 544.5 340.68 L 547 348.18 L 542 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 247px; margin-left: 362px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
/api/{catalog,search}/*
</div>
</div>
</div>
</foreignObject>
<text x="362" y="250" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
/api/{catalog,search}/*
</text>
</switch>
</g>
<path d="M 334.5 106.5 Q 334.5 106.5 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 319.5 113.36 C 319.5 109.57 326.22 106.5 334.5 106.5 C 338.48 106.5 342.29 107.22 345.11 108.51 C 347.92 109.79 349.5 111.54 349.5 113.36 L 349.5 144.64 C 349.5 148.43 342.78 151.5 334.5 151.5 C 326.22 151.5 319.5 148.43 319.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 349.5 113.36 C 349.5 117.14 342.78 120.21 334.5 120.21 C 326.22 120.21 319.5 117.14 319.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 409.5 106.5 Q 409.5 87.78 372 87.78 Q 334.5 87.78 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 394.5 113.36 C 394.5 109.57 401.22 106.5 409.5 106.5 C 413.48 106.5 417.29 107.22 420.11 108.51 C 422.92 109.79 424.5 111.54 424.5 113.36 L 424.5 144.64 C 424.5 148.43 417.78 151.5 409.5 151.5 C 401.22 151.5 394.5 148.43 394.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 424.5 113.36 C 424.5 117.14 417.78 120.21 409.5 120.21 C 401.22 120.21 394.5 117.14 394.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 492 106.5 Q 492 87.78 518.25 87.78 Q 544.5 87.78 544.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 544.5 70.68 L 547 78.18 L 542 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 477 113.36 C 477 109.57 483.72 106.5 492 106.5 C 495.98 106.5 499.79 107.22 502.61 108.51 C 505.42 109.79 507 111.54 507 113.36 L 507 144.64 C 507 148.43 500.28 151.5 492 151.5 C 483.72 151.5 477 148.43 477 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 507 113.36 C 507 117.14 500.28 120.21 492 120.21 C 483.72 120.21 477 117.14 477 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 597 106.5 Q 597 87.78 570.75 87.78 Q 544.5 87.78 544.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 544.5 70.68 L 547 78.18 L 542 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 582 113.36 C 582 109.57 588.72 106.5 597 106.5 C 600.98 106.5 604.79 107.22 607.61 108.51 C 610.42 109.79 612 111.54 612 113.36 L 612 144.64 C 612 148.43 605.28 151.5 597 151.5 C 588.72 151.5 582 148.43 582 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 612 113.36 C 612 117.14 605.28 120.21 597 120.21 C 588.72 120.21 582 117.14 582 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 709.5 106.5 Q 709.5 87.78 739.5 87.78 Q 769.5 87.78 769.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 769.5 70.68 L 772 78.18 L 767 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 694.5 113.36 C 694.5 109.57 701.22 106.5 709.5 106.5 C 713.48 106.5 717.29 107.22 720.11 108.51 C 722.92 109.79 724.5 111.54 724.5 113.36 L 724.5 144.64 C 724.5 148.43 717.78 151.5 709.5 151.5 C 701.22 151.5 694.5 148.43 694.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 724.5 113.36 C 724.5 117.14 717.78 120.21 709.5 120.21 C 701.22 120.21 694.5 117.14 694.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 829.5 106.5 Q 829.5 87.78 799.5 87.78 Q 769.5 87.78 769.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 769.5 70.68 L 772 78.18 L 767 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 814.5 113.36 C 814.5 109.57 821.22 106.5 829.5 106.5 C 833.48 106.5 837.29 107.22 840.11 108.51 C 842.92 109.79 844.5 111.54 844.5 113.36 L 844.5 144.64 C 844.5 148.43 837.78 151.5 829.5 151.5 C 821.22 151.5 814.5 148.43 814.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 844.5 113.36 C 844.5 117.14 837.78 120.21 829.5 120.21 C 821.22 120.21 814.5 117.14 814.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 259.5 106.5 Q 259.5 87.78 297 87.78 Q 334.5 87.78 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 244.5 113.36 C 244.5 109.57 251.22 106.5 259.5 106.5 C 263.48 106.5 267.29 107.22 270.11 108.51 C 272.92 109.79 274.5 111.54 274.5 113.36 L 274.5 144.64 C 274.5 148.43 267.78 151.5 259.5 151.5 C 251.22 151.5 244.5 148.43 244.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 274.5 113.36 C 274.5 117.14 267.78 120.21 259.5 120.21 C 251.22 120.21 244.5 117.14 244.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 229.5 99 L 218.25 99 Q 207 99 207 114 L 207 121.5 Q 207 129 195.75 129 L 190.13 129 Q 184.5 129 195.75 129 L 201.38 129 Q 207 129 207 144 L 207 151.5 Q 207 159 218.25 159 L 229.5 159" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
<rect x="19.5" y="286.5" width="165" height="45" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 206px; margin-left: 13px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="">
Horizontally Scaled
</span>
<br style="border-color: var(--border-color);"/>
<span style="">
Deployments
</span>
</div>
</div>
</div>
</foreignObject>
<text x="121" y="210" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
Horizontally Scale...
</text>
</switch>
</g>
<rect x="19.5" y="106.5" width="165" height="45" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 86px; margin-left: 13px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Logical Databases
</div>
</div>
</div>
</foreignObject>
<text x="121" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
Logical Databases
</text>
</switch>
</g>
<path d="M 319.5 53.36 C 319.5 49.57 326.22 46.5 334.5 46.5 C 338.48 46.5 342.29 47.22 345.11 48.51 C 347.92 49.79 349.5 51.54 349.5 53.36 L 349.5 62.14 C 349.5 65.93 342.78 69 334.5 69 C 326.22 69 319.5 65.93 319.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 349.5 53.36 C 349.5 57.14 342.78 60.21 334.5 60.21 C 326.22 60.21 319.5 57.14 319.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 319.5 45.86 C 319.5 42.07 326.22 39 334.5 39 C 338.48 39 342.29 39.72 345.11 41.01 C 347.92 42.29 349.5 44.04 349.5 45.86 L 349.5 54.64 C 349.5 58.43 342.78 61.5 334.5 61.5 C 326.22 61.5 319.5 58.43 319.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 349.5 45.86 C 349.5 49.64 342.78 52.71 334.5 52.71 C 326.22 52.71 319.5 49.64 319.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 319.5 38.36 C 319.5 34.57 326.22 31.5 334.5 31.5 C 338.48 31.5 342.29 32.22 345.11 33.51 C 347.92 34.79 349.5 36.54 349.5 38.36 L 349.5 47.14 C 349.5 50.93 342.78 54 334.5 54 C 326.22 54 319.5 50.93 319.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 349.5 38.36 C 349.5 42.14 342.78 45.21 334.5 45.21 C 326.22 45.21 319.5 42.14 319.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 529.5 53.36 C 529.5 49.57 536.22 46.5 544.5 46.5 C 548.48 46.5 552.29 47.22 555.11 48.51 C 557.92 49.79 559.5 51.54 559.5 53.36 L 559.5 62.14 C 559.5 65.93 552.78 69 544.5 69 C 536.22 69 529.5 65.93 529.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 559.5 53.36 C 559.5 57.14 552.78 60.21 544.5 60.21 C 536.22 60.21 529.5 57.14 529.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 529.5 45.86 C 529.5 42.07 536.22 39 544.5 39 C 548.48 39 552.29 39.72 555.11 41.01 C 557.92 42.29 559.5 44.04 559.5 45.86 L 559.5 54.64 C 559.5 58.43 552.78 61.5 544.5 61.5 C 536.22 61.5 529.5 58.43 529.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 559.5 45.86 C 559.5 49.64 552.78 52.71 544.5 52.71 C 536.22 52.71 529.5 49.64 529.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 529.5 38.36 C 529.5 34.57 536.22 31.5 544.5 31.5 C 548.48 31.5 552.29 32.22 555.11 33.51 C 557.92 34.79 559.5 36.54 559.5 38.36 L 559.5 47.14 C 559.5 50.93 552.78 54 544.5 54 C 536.22 54 529.5 50.93 529.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 559.5 38.36 C 559.5 42.14 552.78 45.21 544.5 45.21 C 536.22 45.21 529.5 42.14 529.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 754.5 53.36 C 754.5 49.57 761.22 46.5 769.5 46.5 C 773.48 46.5 777.29 47.22 780.11 48.51 C 782.92 49.79 784.5 51.54 784.5 53.36 L 784.5 62.14 C 784.5 65.93 777.78 69 769.5 69 C 761.22 69 754.5 65.93 754.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 784.5 53.36 C 784.5 57.14 777.78 60.21 769.5 60.21 C 761.22 60.21 754.5 57.14 754.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 754.5 45.86 C 754.5 42.07 761.22 39 769.5 39 C 773.48 39 777.29 39.72 780.11 41.01 C 782.92 42.29 784.5 44.04 784.5 45.86 L 784.5 54.64 C 784.5 58.43 777.78 61.5 769.5 61.5 C 761.22 61.5 754.5 58.43 754.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 784.5 45.86 C 784.5 49.64 777.78 52.71 769.5 52.71 C 761.22 52.71 754.5 49.64 754.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 754.5 38.36 C 754.5 34.57 761.22 31.5 769.5 31.5 C 773.48 31.5 777.29 32.22 780.11 33.51 C 782.92 34.79 784.5 36.54 784.5 38.36 L 784.5 47.14 C 784.5 50.93 777.78 54 769.5 54 C 761.22 54 754.5 50.93 754.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 784.5 38.36 C 784.5 42.14 777.78 45.21 769.5 45.21 C 761.22 45.21 754.5 42.14 754.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 229.5 20.25 L 218.25 20.25 Q 207 20.25 207 35.25 L 207 42.75 Q 207 50.25 195.75 50.25 L 190.13 50.25 Q 184.5 50.25 195.75 50.25 L 201.38 50.25 Q 207 50.25 207 65.25 L 207 72.75 Q 207 80.25 218.25 80.25 L 229.5 80.25" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 34px; margin-left: 13px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
DBMS Instances
</div>
</div>
</div>
</foreignObject>
<text x="121" y="37" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
DBMS Instances
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 46 KiB

@@ -140,3 +140,13 @@ backend.start();
```
We've now split the backend into two separate deployments, but we still need to make sure that they can communicate with each other. This is the hard and somewhat tedious part, as Backstage currently doesn't provide an out of the box solution that solves this. You'll need to manually configure the two backends with custom implementations of the `DiscoveryService` and have them return the correct URLs for each other. Likewise, you'll also need to provide a custom implementation of the `DiscoveryApi` in the frontend, unless you surface the two backends via a proxy that handles the routing instead.
### Split backend deployments architecture example
Below is an example of a more elaborate setup where we have three different backend deployments, each with their own set of plugins and modules. Between our frontend app and the backend instances we have a reverse proxy that routes the traffic to the appropriate instance. As an option for securing the Backstage deployment the proxy can be set up as an authenticating reverse proxy as well, denying unauthenticated users access to the backend instances.
![diagram of a backstage deployment with three separate horizontally scaled backend systems](../../assets/backend-system/scaled-deployments.drawio.svg)
In this example we have split out the Catalog and Search plugins into one backend deployment. The proxy routes all traffic for `/api/catalog/` and `/api/search/` to this instance. With this separation we're able to scale and deploy these two plugins independently, and they are also isolated from both a performance and security perspective. Likewise the TechDocs and Scaffolder plugins are split out as well, and then we route the rest of the traffic to our instance that contains the App, Auth, and Proxy plugins.
We also see how each of the plugins have their own logical database, but are often set up to share the actual Database Management System (DBMS) instance. This is of course not a requirement, and you can choose to further divide or consolidate the databases as you see fit.
@@ -754,3 +754,255 @@ going easily, but feel free to move it out to where it fits best. As you migrate
your entire plugin flora to the new backend system, you will probably make more
and more of these modules as "first class" things, living right next to the
implementations that they represent, and being exported from there.
### The Auth Plugin
A basic installation of the auth plugin with a Microsoft provider will look as follows.
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
/* highlight-add-end */
```
An additional step you'll need to take is to add the resolvers to your configuration, here's an example:
```yaml title:"app-config.yaml"
auth:
environment: development
providers:
microsoft:
development:
clientId: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_SECRET}
tenantId: ${AZURE_TENANT_ID}
signIn:
resolvers:
- resolver: emailMatchingUserEntityAnnotation
- resolver: emailMatchingUserEntityProfileEmail
- resolver: emailLocalPartMatchingUserEntityName
```
> Note: the resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
#### Auth Plugin Modules and Their Resolvers
As you may have noticed in the above example you'll need to import the `auth-backend` and an `auth-backend-module`. The following sections outline each of them and their resolvers.
All of the following modules include the following common resolvers:
- [emailMatchingUserEntityProfileEmail](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L29)
- [emailLocalPartMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L54)
##### Atlassian
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts#L33C16-L33C46)
##### GCP IAM
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gcp-iap-provider/src/resolvers.ts#L32C16-L32C49)
##### GitHub
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-github-provider/src/resolvers.ts#L33C16-L33C46)
##### GitLab
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gitlab-provider/src/resolvers.ts#L33C16-L33C46)
##### Google
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-google-provider/src/resolvers.ts#L33C16-L33C49)
##### Microsoft
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-microsoft-provider/src/resolvers.ts#L33C16-L33C49)
##### oauth2
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-oauth2-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-provider/src/resolvers.ts#L33C16-L33C46)
##### oauth2 Proxy
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(
import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'),
);
/* highlight-add-end */
```
Additional resolvers:
- [forwardedUserMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts#L27C16-L27C51)
##### Okta
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-okta-provider'));
/* highlight-add-end */
```
Additional resolvers:
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-okta-provider/src/resolvers.ts#L34C16-L34C49)
##### Pinniped
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));
/* highlight-add-end */
```
##### VMware Cloud
Setup:
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(
import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'),
);
/* highlight-add-end */
```
Additional resolvers:
- [vmwareCloudSignInResolvers](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts#L29C18-L29C44)
#### Custom Resolver
You may have a case where the common resolvers or the ones that are included with the auth module you use won't work for your needs. In this case you will need to create a custom resolver. Instead of the 2nd import for your auth provider module you would provide your own:
```ts title="packages/backend/src/index.ts"
/* highlight-add-start */
export const authModuleGoogleProvider = createBackendModule({
pluginId: 'auth',
moduleId: 'googleProvider',
register(reg) {
reg.registerInit({
deps: { providers: authProvidersExtensionPoint },
async init({ providers }) {
providers.registerProvider({
providerId: 'google',
factory: createOAuthProviderFactory({
authenticator: googleAuthenticator,
async signInResolver(info, ctx) {
// custom resolver ...
},
}),
});
},
});
},
});
/* highlight-add-end */
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(authModuleGoogleProvider);
/* highlight-add-end */
```
+63 -5
View File
@@ -65,20 +65,72 @@ This is an array used to determine where to retrieve cluster configuration from.
Valid cluster locator methods are:
- [`catalog`](#catalog)
- [`localKubectlProxy`](#localkubectlproxy)
- [`config`](#config)
- [`gke`](#gke)
- [`localKubectlProxy`](#localkubectlproxy)
- [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier)
#### `catalog`
This cluster locator method will read cluster information from the catalog.
This cluster locator method will gather
[Resources](https://backstage.io/docs/features/software-catalog/system-model#resource)
of
[type](https://backstage.io/docs/features/software-catalog/descriptor-format#spectype-required-4)
`kubernetes-cluster` from the catalog and treat them as clusters for the
purposes of the Kubernetes plugin. In order for a resource to be detected by
this method, it must also have the following
[annotations](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional)
(as seen
[here](https://github.com/backstage/backstage/blob/86baccb2d7d378baed74eaebf017c60b410986e5/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts#L51-L61)
in the code):
#### `localKubectlProxy`
- [`kubernetes.io/api-server`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server/),
denoting the base URL of the Kubernetes control plane
- [`kubernetes.io/api-server-certificate-authority`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server_ca/),
containing a base64-encoded certificate authority bundle in PEM format;
Backstage will check that the control plane presents a certificate signed by
this authority.
- [`kubernetes.io/auth-provider`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_auth_provider/),
denoting the strategy to use to authenticate with the control plane.
This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001).
There are many other annotations that can be applied to a cluster resource to
configure the way Backstage communicates, documented
[here](https://backstage.io/docs/reference/plugin-kubernetes-common#variables)
in the API reference. Here is a YAML snippet illustrating an example of a
cluster in the catalog:
NOTE: This cluster locator method is for local development only and should not be used in production.
```yaml
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
name: my-cluster
annotations:
kubernetes.io/api-server: 'https://127.0.0.1:53725'
kubernetes.io/api-server-certificate-authority: # base64-encoded CA
kubernetes.io/auth-provider: 'oidc'
kubernetes.io/oidc-token-provider: 'microsoft'
kubernetes.io/skip-metrics-lookup: 'true'
spec:
type: kubernetes-cluster
owner: user:guest
```
Note that it is insecure to store a Kubernetes service account token in an
annotation on a catalog entity (where it could easily be accidentally revealed
by the catalog API) -- therefore there is no annotation corresponding to the
[`serviceAccountToken` field](#clustersserviceaccounttoken-optional) used by
the [`config`](#config) cluster locator. Accordingly, the catalog cluster
locator does not support the [`serviceAccount`](#clustersauthprovider) auth
strategy.
This method can be quite helpful when used in combination with an ingestion
procedure like the
[`GkeEntityProvider`](https://backstage.io/docs/reference/plugin-catalog-backend-module-gcp.gkeentityprovider/)
(installation documented
[here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-gcp#installation))
or the
[`AwsEKSClusterProcessor`](https://backstage.io/docs/reference/plugin-catalog-backend-module-aws.awseksclusterprocessor/)
to automatically update the set of clusters tracked by Backstage.
#### `config`
@@ -388,6 +440,12 @@ Defaults to `false`.
Array of key value labels used to filter out clusters which don't have the matching
[resource labels](https://cloud.google.com/resource-manager/docs/creating-managing-labels).
#### `localKubectlProxy`
This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001).
NOTE: This cluster locator method is for local development only and should not be used in production.
#### Custom `KubernetesClustersSupplier`
If the configuration-based cluster locators do not work for your use-case,
@@ -51,18 +51,19 @@ _Example disabling the search page extension_
# app-config.yaml
app:
extensions:
- plugin.search.page: false # ✨
- page:search: false # ✨
- nav-item:search: false # ✨
```
_Example setting the search sidebar item label_
_Example setting the search sidebar item title_
```yaml
# app-config.yaml
app:
extensions:
- plugin.search.nav.index: # ✨
- nav-item:search: # ✨
config:
label: 'Search Page'
title: 'Search Page'
```
> **Known limitations:**
@@ -782,7 +782,7 @@ Describes the following entity kind:
An API describes an interface that can be exposed by a component. The API can be
defined in different formats, like [OpenAPI](https://swagger.io/specification/),
[AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/),
[AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest),
[GraphQL](https://graphql.org/learn/schema/),
[gRPC](https://developers.google.com/protocol-buffers), or other formats.
@@ -838,7 +838,7 @@ The current set of well-known and common values for this field is:
- `openapi` - An API definition in YAML or JSON format based on the
[OpenAPI](https://swagger.io/specification/) version 2 or version 3 spec.
- `asyncapi` - An API definition based on the
[AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/) spec.
[AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest) spec.
- `graphql` - An API definition based on
[GraphQL schemas](https://spec.graphql.org/) for consuming
[GraphQL](https://graphql.org/) based APIs.
@@ -128,10 +128,10 @@ class ExamplePermissionPolicy implements PermissionPolicy {
}
```
With this permission policy, the user `spiderman` won't be able to execute the debug:log action.
With this permission policy, the user `spiderman` won't be able to execute the `debug:log` action.
You can also restrict the input provided to the action by combining multiple rules.
In the example below, `spiderman` won't be able to execute debug:log when passing `{ "message": "not-this!" }` as action input:
In the example below, `spiderman` won't be able to execute `debug:log` when passing `{ "message": "not-this!" }` as action input:
```ts title="packages/backend/src/plugins/permission.ts"
/* highlight-add-start */
+81 -36
View File
@@ -8,9 +8,17 @@ For some use cases, you may want to define custom [rules](./concepts.md#resource
## Define a custom rule
Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule in `packages/backend/src/customPermissionRules/isInSystem.ts`, but you can put it anywhere that's accessible by your `backend` package.
Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule and create a condition in `packages/backend/src/plugins/permission.ts`.
We use Zod in our example below. To install, run:
```bash
yarn workspace backend add zod
```
```typescript title="packages/backend/src/plugins/permission.ts"
...
```typescript title="packages/backend/src/customPermissionRules/isInSystem.ts"
import type { Entity } from '@backstage/catalog-model';
import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
import { createConditionFactory } from '@backstage/plugin-permission-node';
@@ -40,43 +48,56 @@ export const isInSystemRule = createCatalogPermissionRule({
}),
});
export const isInSystemRuleFactory = createConditionFactory(isInSystemRule);
const isInSystem = createConditionFactory(isInSystemRule);
...
```
For a more detailed explanation on defining rules, refer to the [documentation for plugin authors](./plugin-authors/03-adding-a-resource-permission-check.md#adding-support-for-conditional-decisions).
## Provide the rule during plugin setup
Now that we have a custom rule defined, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime.
The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`.
```typescript title="packages/backend/src/plugins/catalog.ts"
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
import { isInSystemRule } from '../customPermissionRules/isInSystem';
...
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);
builder.addPermissionRules(isInSystemRule);
...
return router;
}
```
The new rule is now ready for use in a permission policy!
## Use the rule in a policy
Let's bring this all together by extending the example policy from the previous section.
Still in the `packages/backend/src/plugins/permission.ts` file, let's use the condition we just created in our `TestPermissionPolicy`.
```ts title="packages/backend/src/plugins/permission.ts"
...
/* highlight-remove-next-line */
import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
/* highlight-add-next-line */
import { isInSystemRuleFactory } from '../customPermissionRules/isInSystem';
import { catalogConditions, createCatalogConditionalDecision, createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
/* highlight-remove-next-line */
import { createConditionFactory } from '@backstage/plugin-permission-node';
/* highlight-add-next-line */
import { PermissionPolicy, PolicyQuery, createConditionFactory } from '@backstage/plugin-permission-node';
/* highlight-add-start */
import { BackstageIdentityResponse } from '@backstage/plugin-auth-node';
import { AuthorizeResult, PolicyDecision, isResourcePermission } from '@backstage/plugin-permission-common';
/* highlight-add-end */
...
export const isInSystemRule = createCatalogPermissionRule({
name: 'IS_IN_SYSTEM',
description: 'Checks if an entity is part of the system provided',
resourceType: 'catalog-entity',
paramsSchema: z.object({
systemRef: z
.string()
.describe('SystemRef to check the resource is part of'),
}),
apply: (resource: Entity, { systemRef }) => {
if (!resource.relations) {
return false;
}
return resource.relations
.filter(relation => relation.type === 'partOf')
.some(relation => relation.targetRef === systemRef);
},
toQuery: ({ systemRef }) => ({
key: 'relations.partOf',
values: [systemRef],
}),
});
const isInSystem = createConditionFactory(isInSystemRule);
class TestPermissionPolicy implements PermissionPolicy {
async handle(
@@ -95,11 +116,11 @@ class TestPermissionPolicy implements PermissionPolicy {
{
anyOf: [
catalogConditions.isEntityOwner({
claims: user?.identity.ownershipEntityRefs ?? []
claims: user?.identity.ownershipEntityRefs ?? [],
}),
isInSystemRuleFactory({ systemRef: 'interviewing' }),
]
}
isInSystem({ systemRef: 'interviewing' }),
],
},
/* highlight-add-end */
);
}
@@ -111,7 +132,31 @@ class TestPermissionPolicy implements PermissionPolicy {
...
```
## Provide the rule during plugin setup
Now that we have a custom rule defined and added to our policy, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime.
The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`.
```typescript title="packages/backend/src/plugins/catalog.ts"
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
/* highlight-add-next-line */
import { isInSystemRule } from './permission';
...
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);
/* highlight-add-next-line */
builder.addPermissionRules(isInSystemRule);
...
return router;
}
```
The updated policy will allow catalog entity resource permissions if any of the following are true:
- User owns the target entity
- Target entity is part of the `'interviewing'` system
- Target entity is part of the 'interviewing' system
+7
View File
@@ -53,6 +53,7 @@ Additional steps for the main line release
- Add the release note file as [`/docs/releases/vx.y.0.md`](./releases)
- Add an entry to [`/microsite/sidebar.json`](https://github.com/backstage/backstage/blob/master/microsite/sidebars.json) for the release note
- Update the navigation bar item in [`/microsite/docusaurus.config.js`](https://github.com/backstage/backstage/blob/master/microsite/docusaurus.config.js) to point to the new release note
- Finally copy the content, without the metadata header, into the description of the [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages)
Once the release has been published edit the newly created release in the [GitHub repository](https://github.com/backstage/backstage/releases) and replace the text content with the release notes.
@@ -134,3 +135,9 @@ process is used to release an emergency fix as version `6.5.1` in the patch rele
- [ ] The fix, which you can likely cherry-pick from your patch branch: `git cherry-pick origin/patch/v1.18.0^`
- [ ] An updated `CHANGELOG.md` of all patched packages from the tip of the patch branch, `git checkout origin/patch/v1.18.0 -- {packages,plugins}/*/CHANGELOG.md`. Note that if the patch happens after any next-line releases you'll need to restore those entries in the changelog, placing the patch release entry beneath any next-line release entries.
- [ ] A changeset with the message "Applied the fix from version `6.5.1` of this package, which is part of the `v1.18.1` release of Backstage."
## Troubleshooting
### When the release workflow is not triggered for some reason, such as a GitHub incident
Ask one of the maintainers to force push master back to a previous commit and then push the release merge commit again.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
---
id: v1.22.0
title: v1.22.0
description: Backstage Release v1.22.0
---
These are the release notes for the v1.22.0 release of [Backstage](https://backstage.io/).
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
## Highlights
### Updates to new frontend system
There have been several updates to alpha packages in the new frontend system including a breaking change where the `app/router` extension was renamed to `app/root`. Furthermore `elements`, `wrappers`, and `router` were added as inputs to `app/root` making it possible to pass extensions into the root of the app.
### Plugins and modules migrated to the New Backend System
Some more features have been migrated to the new backend system:
- `@backstage/plugin-auth-backend-module-microsoft-provider`
- `@backstage/plugin-auth-backend-module-pinniped-provider`
- `@backstage/plugin-catalog-backend-module-openapi`
- `@backstage/plugin-events-backend-module-azure`
- `@backstage/plugin-events-backend-module-bitbucket-cloud`
- `@backstage/plugin-events-backend-module-gerrit`
- `@backstage/plugin-linguist`
### New plugin: App Visualizer
This release includes the new `@backstage/plugin-app-visualizer` package. This plugin for the new frontend system lets you browse and view the extension structure of your app as a graph, detailed list, or in text form.
### New feature: Dynamic Feature Service
This release includes the new `@backstage/backend-dynamic-feature-service` package.
It is a new and experimental service that lets you dynamically detect and load local plugins and modules in your Backstage instance.
Contributed by [@davidfestal](https://github.com/davidfestal) in [#18862](https://github.com/backstage/backstage/pull/18862)
### New Scaffolder action `gitlab:issues:create`
You can now create GitHub issues in your scaffolder flows! Contributed by [@elaine-mattos](https://github.com/elaine-mattos) in [#21929](https://github.com/backstage/backstage/pull/21929)
### New Scaffolder action `gitlab:repo:push`
You can now push raw branches to GitLab in your scaffolder flows! Contributed by [@gavlyukovskiy](https://github.com/gavlyukovskiy) in [#21977](https://github.com/backstage/backstage/pull/21977)
## Security Fixes
This release does not contain any security fixes.
However, some updates were made to the build facilities in the CLI and the caches in the backend system, such that you can now perform builds on FIPS compliant systems. This may lead to some internal cache invalidation happening, since the hashing algorithms used were updated. This should not pose a problem unless caches were being used as reliable persistent storage systems. Please let us know if you encounter any issues that may be related to this.
## Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
## Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
- [GitHub repository](https://github.com/backstage/backstage)
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.22.0-changelog.md)
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage.
+1 -1
View File
@@ -56,7 +56,7 @@ For current known issues with the Material UI v5 migration, follow our [Mileston
To migrate your plugin to Material UI v5, you can build on the resources available.
1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size).
1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-material-ui-4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md) rule to help with this.
2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/<path>`.
3. Take a look at possible `TODO:` items the `codemod` could not fix.
4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`.
+1 -1
View File
@@ -5,6 +5,6 @@ authorUrl: https://snyk.io
category: Security
description: View Snyk scanned vulnerabilities and license compliance of your components directly in Backstage.
documentation: https://github.com/snyk-tech-services/backstage-plugin-snyk/blob/main/README.md
iconUrl: https://storage.googleapis.com/snyk-technical-services.appspot.com/snyk-logo-vertical-black.png
iconUrl: https://github.com/snyk-tech-services/backstage-plugin-snyk/assets/109112986/95eb1b06-b3e8-4910-9233-11926e02fa18
npmPackageName: 'backstage-plugin-snyk'
addedDate: '2021-01-22'
+5 -2
View File
@@ -182,7 +182,7 @@ module.exports = {
position: 'left',
},
{
to: 'docs/releases/v1.21.0',
to: 'docs/releases/v1.22.0',
label: 'Releases',
position: 'left',
},
@@ -204,7 +204,10 @@ module.exports = {
{
items: [
{
html: '<a href="/"><h2 class="footerLogo"></h2></a>',
html: `
<a href="/" aria-label="Backstage Home">
<div class="footerLogo"></div>
</a>`,
},
],
},
+1
View File
@@ -6,6 +6,7 @@
"scripts": {
"start": "node scripts/pre-build.js && docusaurus start",
"build": "node scripts/pre-build.js && docusaurus build",
"prettier:fix": "prettier --write .",
"prettier:check": "prettier --check .",
"publish-gh-pages": "docusaurus-publish",
"write-translations": "docusaurus-write-translations",
+1
View File
@@ -1,6 +1,7 @@
{
"releases": {
"Release Notes": [
"releases/v1.22.0",
"releases/v1.21.0",
"releases/v1.20.0",
"releases/v1.19.0",
+2
View File
@@ -95,10 +95,12 @@ const HomePage = () => {
<img
className="laptopSvg"
src={`${siteConfig.baseUrl}img/laptop.svg`}
alt="Illustration of a laptop"
/>
<img
className="laptopScreenGif"
src={`${siteConfig.baseUrl}animations/backstage-logos-hero-8.gif`}
alt="Animated Backstage Logo"
/>
</div>
</BannerSectionGrid>
+6
View File
@@ -151,6 +151,12 @@ const Plugins = () => {
{showOtherPlugins && (
<div>
<h2>All Plugins</h2>
<p>
Friendly reminder: While we love the variety and contributions of
our open source plugins, they haven't been fully vetted by the
core Backstage team. We encourage you to exercise caution and do
your due diligence before installing. Happy exploring!
</p>
<div className="pluginsContainer margin-bottom--lg">
{plugins.otherPlugins
.filter(
+8
View File
@@ -8,6 +8,14 @@
--ifm-color-primary-darkest: #268271;
}
#__docusaurus {
.theme-doc-markdown {
a {
text-decoration: underline;
}
}
}
.footerLogo {
background-image: url(/img/logo.svg);
background-repeat: no-repeat;
+6 -6
View File
@@ -3055,9 +3055,9 @@ __metadata:
linkType: hard
"@types/luxon@npm:^3.0.0":
version: 3.3.7
resolution: "@types/luxon@npm:3.3.7"
checksum: 97026557e92bcba308a5592f981591cd200d493fc8997874d79acecf6a2ec41debeded3ac5cd80c371ef7f6f56cc0d1be0a5aca846e03d3e6b4a2be37256fe2f
version: 3.3.8
resolution: "@types/luxon@npm:3.3.8"
checksum: 026711b4aefc01c6e233e359c693b6d4c0873acc3f52a08661ea3751b2cf3e34d1ce1d5b0b99b0e40a059a2a3755acc20498d37db5f9a5a4f0f330cdf72db3db
languageName: node
linkType: hard
@@ -5874,12 +5874,12 @@ __metadata:
linkType: hard
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.9":
version: 1.15.2
resolution: "follow-redirects@npm:1.15.2"
version: 1.15.4
resolution: "follow-redirects@npm:1.15.4"
peerDependenciesMeta:
debug:
optional: true
checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190
checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6
languageName: node
linkType: hard
+4 -1
View File
@@ -6,8 +6,11 @@
},
"scripts": {
"dev": "concurrently 'yarn start' 'yarn start-backend'",
"dev:next": "concurrently 'yarn start:next' 'yarn start-backend:next'",
"start": "yarn workspace example-app start",
"start-backend": "yarn workspace example-backend start",
"start:next": "yarn workspace example-app-next start",
"start-backend:next": "yarn workspace example-backend-next start",
"build:backend": "yarn workspace example-backend build",
"build:all": "backstage-cli repo build --all",
"build:api-reports": "yarn build:api-reports:only --tsc",
@@ -53,7 +56,7 @@
"@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch",
"@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch"
},
"version": "1.22.0-next.1",
"version": "1.22.0",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3",
+11
View File
@@ -1,5 +1,16 @@
# @backstage/app-defaults
## 1.4.7
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.13.10
- @backstage/core-plugin-api@1.8.2
- @backstage/plugin-permission-react@0.4.19
- @backstage/core-app-api@1.11.3
- @backstage/theme@0.5.0
## 1.4.7-next.1
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.4.7-next.1",
"version": "1.4.7",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
@@ -1,5 +1,20 @@
# app-next-example-plugin
## 0.0.5
### Patch Changes
- Updated dependencies
- @backstage/frontend-plugin-api@0.5.0
- @backstage/core-components@0.13.10
## 0.0.5-next.2
### Patch Changes
- Updated dependencies
- @backstage/frontend-plugin-api@0.4.1-next.2
## 0.0.5-next.1
### Patch Changes
@@ -1,7 +1,7 @@
{
"name": "app-next-example-plugin",
"description": "Backstage internal example plugin",
"version": "0.0.5-next.1",
"version": "0.0.5",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+141
View File
@@ -1,5 +1,146 @@
# example-app-next
## 0.0.5
### Patch Changes
- Updated dependencies
- @backstage/plugin-api-docs@0.10.3
- @backstage/core-compat-api@0.1.1
- @backstage/plugin-scaffolder-react@1.7.1
- @backstage/frontend-plugin-api@0.5.0
- @backstage/core-components@0.13.10
- @backstage/plugin-user-settings@0.8.0
- @backstage/plugin-azure-sites@0.1.18
- @backstage/cli@0.25.1
- @backstage/core-plugin-api@1.8.2
- @backstage/plugin-octopus-deploy@0.2.11
- @backstage/frontend-app-api@0.5.0
- @backstage/plugin-kubernetes@0.11.4
- @backstage/plugin-home@0.6.1
- @backstage/plugin-scaffolder@1.17.1
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4
- @backstage/plugin-catalog-unprocessed-entities@0.1.7
- @backstage/plugin-microsoft-calendar@0.1.11
- @backstage/plugin-newrelic-dashboard@0.3.4
- @backstage/plugin-permission-react@0.4.19
- @backstage/plugin-entity-feedback@0.2.12
- @backstage/plugin-apache-airflow@0.2.19
- @backstage/plugin-github-actions@0.6.10
- @backstage/plugin-techdocs-react@1.1.15
- @backstage/plugin-catalog-graph@0.3.3
- @backstage/plugin-catalog-react@1.9.3
- @backstage/plugin-code-coverage@0.2.22
- @backstage/plugin-cost-insights@0.12.18
- @backstage/plugin-tech-insights@0.3.21
- @backstage/plugin-azure-devops@0.3.11
- @backstage/plugin-gcp-projects@0.3.45
- @backstage/plugin-cloudbuild@0.3.29
- @backstage/plugin-lighthouse@0.4.14
- @backstage/plugin-stackstorm@0.1.10
- @backstage/plugin-tech-radar@0.6.12
- @backstage/plugin-dynatrace@8.0.3
- @backstage/plugin-gcalendar@0.3.22
- @backstage/plugin-pagerduty@0.7.1
- @backstage/plugin-shortcuts@0.3.18
- @backstage/plugin-airbrake@0.3.29
- @backstage/plugin-devtools@0.1.8
- @backstage/plugin-graphiql@0.3.2
- @backstage/plugin-linguist@0.1.14
- @backstage/plugin-newrelic@0.3.44
- @backstage/plugin-playlist@0.2.3
- @backstage/plugin-puppetdb@0.1.12
- @backstage/plugin-techdocs@1.9.3
- @backstage/plugin-catalog@1.16.1
- @backstage/plugin-explore@0.4.15
- @backstage/plugin-jenkins@0.9.4
- @backstage/plugin-rollbar@0.4.29
- @backstage/plugin-badges@0.2.53
- @backstage/plugin-search@1.4.5
- @backstage/plugin-sentry@0.5.14
- @backstage/plugin-kafka@0.3.29
- @backstage/plugin-gocd@0.1.35
- @backstage/plugin-todo@0.2.33
- @backstage/plugin-adr@0.6.12
- @backstage/plugin-org@0.6.19
- @backstage/plugin-app-visualizer@0.1.0
- @backstage/plugin-catalog-import@0.10.5
- app-next-example-plugin@0.0.5
- @backstage/plugin-search-react@1.7.5
- @backstage/app-defaults@1.4.7
- @backstage/integration-react@1.1.23
- @backstage/catalog-model@1.4.3
- @backstage/core-app-api@1.11.3
- @backstage/theme@0.5.0
- @backstage/plugin-catalog-common@1.0.20
- @backstage/plugin-linguist-common@0.1.2
- @backstage/plugin-search-common@1.2.10
## 0.0.5-next.2
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.1.1-next.2
- @backstage/plugin-user-settings@0.8.0-next.2
- @backstage/plugin-octopus-deploy@0.2.11-next.2
- @backstage/frontend-plugin-api@0.4.1-next.2
- @backstage/frontend-app-api@0.4.1-next.2
- @backstage/plugin-home@0.6.1-next.2
- @backstage/plugin-scaffolder-react@1.7.1-next.2
- @backstage/plugin-scaffolder@1.17.1-next.2
- @backstage/plugin-linguist@0.1.14-next.2
- @backstage/plugin-catalog@1.16.1-next.2
- @backstage/plugin-catalog-import@0.10.5-next.2
- @backstage/plugin-graphiql@0.3.2-next.2
- @backstage/plugin-search@1.4.5-next.2
- @backstage/plugin-tech-radar@0.6.12-next.2
- @backstage/plugin-techdocs@1.9.3-next.2
- app-next-example-plugin@0.0.5-next.2
- @backstage/plugin-adr@0.6.12-next.2
- @backstage/plugin-catalog-react@1.9.3-next.2
- @backstage/plugin-explore@0.4.15-next.2
- @backstage/plugin-search-react@1.7.5-next.2
- @backstage/plugin-visualizer@0.0.2-next.2
- @backstage/cli@0.25.1-next.1
- @backstage/plugin-pagerduty@0.7.1-next.2
- @backstage/plugin-api-docs@0.10.3-next.2
- @backstage/plugin-catalog-graph@0.3.3-next.2
- @backstage/plugin-org@0.6.19-next.2
- @backstage/plugin-airbrake@0.3.29-next.2
- @backstage/plugin-azure-devops@0.3.11-next.2
- @backstage/plugin-azure-sites@0.1.18-next.2
- @backstage/plugin-badges@0.2.53-next.2
- @backstage/plugin-cloudbuild@0.3.29-next.2
- @backstage/plugin-code-coverage@0.2.22-next.2
- @backstage/plugin-cost-insights@0.12.18-next.2
- @backstage/plugin-dynatrace@8.0.3-next.2
- @backstage/plugin-entity-feedback@0.2.12-next.2
- @backstage/plugin-github-actions@0.6.10-next.2
- @backstage/plugin-gocd@0.1.35-next.2
- @backstage/plugin-jenkins@0.9.4-next.2
- @backstage/plugin-kafka@0.3.29-next.2
- @backstage/plugin-kubernetes@0.11.4-next.2
- @backstage/plugin-lighthouse@0.4.14-next.2
- @backstage/plugin-newrelic-dashboard@0.3.4-next.2
- @backstage/plugin-playlist@0.2.3-next.2
- @backstage/plugin-puppetdb@0.1.12-next.2
- @backstage/plugin-rollbar@0.4.29-next.2
- @backstage/plugin-sentry@0.5.14-next.2
- @backstage/plugin-tech-insights@0.3.21-next.2
- @backstage/plugin-todo@0.2.33-next.2
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
- @backstage/integration-react@1.1.23-next.0
- @backstage/plugin-apache-airflow@0.2.19-next.1
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
- @backstage/plugin-devtools@0.1.8-next.1
- @backstage/plugin-gcalendar@0.3.22-next.1
- @backstage/plugin-gcp-projects@0.3.45-next.1
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
- @backstage/plugin-newrelic@0.3.44-next.1
- @backstage/plugin-shortcuts@0.3.18-next.1
- @backstage/plugin-stackstorm@0.1.10-next.1
## 0.0.5-next.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "example-app-next",
"version": "0.0.5-next.1",
"version": "0.0.5",
"private": true,
"backstage": {
"role": "frontend"
@@ -21,6 +21,7 @@
"@backstage/plugin-airbrake": "workspace:^",
"@backstage/plugin-apache-airflow": "workspace:^",
"@backstage/plugin-api-docs": "workspace:^",
"@backstage/plugin-app-visualizer": "workspace:^",
"@backstage/plugin-azure-devops": "workspace:^",
"@backstage/plugin-azure-sites": "workspace:^",
"@backstage/plugin-badges": "workspace:^",
@@ -74,7 +75,6 @@
"@backstage/plugin-techdocs-react": "workspace:^",
"@backstage/plugin-todo": "workspace:^",
"@backstage/plugin-user-settings": "workspace:^",
"@backstage/plugin-visualizer": "workspace:^",
"@backstage/theme": "workspace:^",
"@circleci/backstage-plugin": "^0.1.1",
"@material-ui/core": "^4.12.2",
+1 -1
View File
@@ -32,7 +32,7 @@ import {
createExtensionOverrides,
} from '@backstage/frontend-plugin-api';
import techdocsPlugin from '@backstage/plugin-techdocs/alpha';
import appVisualizerPlugin from '@backstage/plugin-visualizer';
import appVisualizerPlugin from '@backstage/plugin-app-visualizer';
import { homePage } from './HomePage';
import { convertLegacyApp } from '@backstage/core-compat-api';
import { FlatRoutes } from '@backstage/core-app-api';
+140
View File
@@ -1,5 +1,145 @@
# example-app
## 0.2.91
### Patch Changes
- Updated dependencies
- @backstage/plugin-api-docs@0.10.3
- @backstage/plugin-scaffolder-react@1.7.1
- @backstage/core-components@0.13.10
- @backstage/plugin-user-settings@0.8.0
- @backstage/plugin-azure-sites@0.1.18
- @backstage/cli@0.25.1
- @backstage/core-plugin-api@1.8.2
- @backstage/plugin-octopus-deploy@0.2.11
- @backstage/frontend-app-api@0.5.0
- @backstage/plugin-kubernetes@0.11.4
- @backstage/plugin-home@0.6.1
- @backstage/plugin-scaffolder@1.17.1
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4
- @backstage/plugin-catalog-unprocessed-entities@0.1.7
- @backstage/plugin-kubernetes-cluster@0.0.5
- @backstage/plugin-microsoft-calendar@0.1.11
- @backstage/plugin-newrelic-dashboard@0.3.4
- @backstage/plugin-permission-react@0.4.19
- @backstage/plugin-entity-feedback@0.2.12
- @backstage/plugin-apache-airflow@0.2.19
- @backstage/plugin-github-actions@0.6.10
- @backstage/plugin-stack-overflow@0.1.24
- @backstage/plugin-techdocs-react@1.1.15
- @backstage/plugin-catalog-graph@0.3.3
- @backstage/plugin-catalog-react@1.9.3
- @backstage/plugin-code-coverage@0.2.22
- @backstage/plugin-cost-insights@0.12.18
- @backstage/plugin-tech-insights@0.3.21
- @backstage/plugin-azure-devops@0.3.11
- @backstage/plugin-gcp-projects@0.3.45
- @backstage/plugin-cloudbuild@0.3.29
- @backstage/plugin-lighthouse@0.4.14
- @backstage/plugin-stackstorm@0.1.10
- @backstage/plugin-tech-radar@0.6.12
- @backstage/plugin-dynatrace@8.0.3
- @backstage/plugin-gcalendar@0.3.22
- @backstage/plugin-pagerduty@0.7.1
- @backstage/plugin-shortcuts@0.3.18
- @backstage/plugin-airbrake@0.3.29
- @backstage/plugin-devtools@0.1.8
- @backstage/plugin-graphiql@0.3.2
- @backstage/plugin-linguist@0.1.14
- @backstage/plugin-newrelic@0.3.44
- @backstage/plugin-playlist@0.2.3
- @backstage/plugin-puppetdb@0.1.12
- @backstage/plugin-techdocs@1.9.3
- @backstage/plugin-catalog@1.16.1
- @backstage/plugin-explore@0.4.15
- @backstage/plugin-jenkins@0.9.4
- @backstage/plugin-rollbar@0.4.29
- @backstage/plugin-badges@0.2.53
- @backstage/plugin-search@1.4.5
- @backstage/plugin-sentry@0.5.14
- @backstage/plugin-kafka@0.3.29
- @backstage/plugin-nomad@0.1.10
- @backstage/plugin-gocd@0.1.35
- @backstage/plugin-todo@0.2.33
- @backstage/plugin-adr@0.6.12
- @backstage/plugin-org@0.6.19
- @backstage/plugin-catalog-import@0.10.5
- @backstage/plugin-search-react@1.7.5
- @backstage/app-defaults@1.4.7
- @backstage/integration-react@1.1.23
- @backstage/catalog-model@1.4.3
- @backstage/config@1.1.1
- @backstage/core-app-api@1.11.3
- @backstage/theme@0.5.0
- @backstage/plugin-catalog-common@1.0.20
- @backstage/plugin-linguist-common@0.1.2
- @backstage/plugin-search-common@1.2.10
## 0.2.91-next.2
### Patch Changes
- Updated dependencies
- @backstage/plugin-user-settings@0.8.0-next.2
- @backstage/plugin-octopus-deploy@0.2.11-next.2
- @backstage/frontend-app-api@0.4.1-next.2
- @backstage/plugin-home@0.6.1-next.2
- @backstage/plugin-scaffolder-react@1.7.1-next.2
- @backstage/plugin-scaffolder@1.17.1-next.2
- @backstage/plugin-linguist@0.1.14-next.2
- @backstage/plugin-catalog@1.16.1-next.2
- @backstage/plugin-catalog-import@0.10.5-next.2
- @backstage/plugin-graphiql@0.3.2-next.2
- @backstage/plugin-search@1.4.5-next.2
- @backstage/plugin-tech-radar@0.6.12-next.2
- @backstage/plugin-techdocs@1.9.3-next.2
- @backstage/plugin-adr@0.6.12-next.2
- @backstage/plugin-catalog-react@1.9.3-next.2
- @backstage/plugin-explore@0.4.15-next.2
- @backstage/plugin-search-react@1.7.5-next.2
- @backstage/plugin-stack-overflow@0.1.24-next.2
- @backstage/cli@0.25.1-next.1
- @backstage/plugin-pagerduty@0.7.1-next.2
- @backstage/plugin-api-docs@0.10.3-next.2
- @backstage/plugin-catalog-graph@0.3.3-next.2
- @backstage/plugin-org@0.6.19-next.2
- @backstage/plugin-airbrake@0.3.29-next.2
- @backstage/plugin-azure-devops@0.3.11-next.2
- @backstage/plugin-azure-sites@0.1.18-next.2
- @backstage/plugin-badges@0.2.53-next.2
- @backstage/plugin-cloudbuild@0.3.29-next.2
- @backstage/plugin-code-coverage@0.2.22-next.2
- @backstage/plugin-cost-insights@0.12.18-next.2
- @backstage/plugin-dynatrace@8.0.3-next.2
- @backstage/plugin-entity-feedback@0.2.12-next.2
- @backstage/plugin-github-actions@0.6.10-next.2
- @backstage/plugin-gocd@0.1.35-next.2
- @backstage/plugin-jenkins@0.9.4-next.2
- @backstage/plugin-kafka@0.3.29-next.2
- @backstage/plugin-kubernetes@0.11.4-next.2
- @backstage/plugin-kubernetes-cluster@0.0.5-next.2
- @backstage/plugin-lighthouse@0.4.14-next.2
- @backstage/plugin-newrelic-dashboard@0.3.4-next.2
- @backstage/plugin-nomad@0.1.10-next.2
- @backstage/plugin-playlist@0.2.3-next.2
- @backstage/plugin-puppetdb@0.1.12-next.2
- @backstage/plugin-rollbar@0.4.29-next.2
- @backstage/plugin-sentry@0.5.14-next.2
- @backstage/plugin-tech-insights@0.3.21-next.2
- @backstage/plugin-todo@0.2.33-next.2
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
- @backstage/integration-react@1.1.23-next.0
- @backstage/plugin-apache-airflow@0.2.19-next.1
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
- @backstage/plugin-devtools@0.1.8-next.1
- @backstage/plugin-gcalendar@0.3.22-next.1
- @backstage/plugin-gcp-projects@0.3.45-next.1
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
- @backstage/plugin-newrelic@0.3.44-next.1
- @backstage/plugin-shortcuts@0.3.18-next.1
- @backstage/plugin-stackstorm@0.1.10-next.1
## 0.2.91-next.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-app",
"version": "0.2.91-next.1",
"version": "0.2.91",
"private": true,
"backstage": {
"role": "frontend"
+32
View File
@@ -1,5 +1,37 @@
# @backstage/backend-app-api
## 0.5.10
### Patch Changes
- 516fd3e: Updated README to reflect release status
- Updated dependencies
- @backstage/backend-common@0.20.1
- @backstage/config-loader@1.6.1
- @backstage/cli-node@0.2.2
- @backstage/backend-plugin-api@0.6.9
- @backstage/plugin-permission-node@0.7.20
- @backstage/backend-tasks@0.5.14
- @backstage/plugin-auth-node@0.4.3
- @backstage/cli-common@0.1.13
- @backstage/config@1.1.1
- @backstage/errors@1.2.3
- @backstage/types@1.1.1
## 0.5.10-next.2
### Patch Changes
- 516fd3e: Updated README to reflect release status
- Updated dependencies
- @backstage/backend-plugin-api@0.6.9-next.2
- @backstage/backend-common@0.20.1-next.2
- @backstage/plugin-auth-node@0.4.3-next.2
- @backstage/plugin-permission-node@0.7.20-next.2
- @backstage/backend-tasks@0.5.14-next.2
- @backstage/cli-node@0.2.2-next.0
- @backstage/config-loader@1.6.1-next.0
## 0.5.10-next.1
### Patch Changes
+1 -3
View File
@@ -1,8 +1,6 @@
# @backstage/backend-app-api
**This package is EXPERIMENTAL, we recommend against using it for production deployments**
This package provides the core API used by Backstage backend apps.
This package provides the framework API used by Backstage backend apps.
## Installation
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.5.10-next.1",
"version": "0.5.10",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+33
View File
@@ -1,5 +1,38 @@
# @backstage/backend-common
## 0.20.1
### Patch Changes
- 3b24eae: Adding support for removing file from git index
- 454d17c: Do not call fetch directly but rather use `fetchResponse` facility
- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches
This can have a side effect of invalidating caches (when cache key was >250 characters)
This improves compliance with FIPS nodejs
- Updated dependencies
- @backstage/config-loader@1.6.1
- @backstage/backend-plugin-api@0.6.9
- @backstage/backend-dev-utils@0.1.3
- @backstage/backend-app-api@0.5.10
- @backstage/cli-common@0.1.13
- @backstage/config@1.1.1
- @backstage/errors@1.2.3
- @backstage/integration@1.8.0
- @backstage/integration-aws-node@0.1.8
- @backstage/types@1.1.1
## 0.20.1-next.2
### Patch Changes
- Updated dependencies
- @backstage/backend-plugin-api@0.6.9-next.2
- @backstage/backend-dev-utils@0.1.3-next.0
- @backstage/backend-app-api@0.5.10-next.2
- @backstage/config-loader@1.6.1-next.0
## 0.20.1-next.1
### Patch Changes
+1
View File
@@ -417,6 +417,7 @@ export class Git {
force?: boolean;
}): Promise<PushResult>;
readCommit(options: { dir: string; sha: string }): Promise<ReadCommitResult>;
remove(options: { dir: string; filepath: string }): Promise<void>;
resolveRef(options: { dir: string; ref: string }): Promise<string>;
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.20.1-next.1",
"version": "0.20.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -105,58 +105,28 @@ export class GithubUrlReader implements UrlReader {
credentials,
);
let response: Response;
try {
response = await fetch(ghUrl, {
headers: {
...credentials?.headers,
...(options?.etag && { 'If-None-Match': options.etag }),
...(options?.lastModifiedAfter && {
'If-Modified-Since': options.lastModifiedAfter.toUTCString(),
}),
Accept: 'application/vnd.github.v3.raw',
},
// TODO(freben): The signal cast is there because pre-3.x versions of
// node-fetch have a very slightly deviating AbortSignal type signature.
// The difference does not affect us in practice however. The cast can
// be removed after we support ESM for CLI dependencies and migrate to
// version 3 of node-fetch.
// https://github.com/backstage/backstage/issues/8242
signal: options?.signal as any,
});
} catch (e) {
throw new Error(`Unable to read ${url}, ${e}`);
}
const response = await this.fetchResponse(ghUrl, {
headers: {
...credentials?.headers,
...(options?.etag && { 'If-None-Match': options.etag }),
...(options?.lastModifiedAfter && {
'If-Modified-Since': options.lastModifiedAfter.toUTCString(),
}),
Accept: 'application/vnd.github.v3.raw',
},
// TODO(freben): The signal cast is there because pre-3.x versions of
// node-fetch have a very slightly deviating AbortSignal type signature.
// The difference does not affect us in practice however. The cast can
// be removed after we support ESM for CLI dependencies and migrate to
// version 3 of node-fetch.
// https://github.com/backstage/backstage/issues/8242
signal: options?.signal as any,
});
if (response.status === 304) {
throw new NotModifiedError();
}
if (response.ok) {
return ReadUrlResponseFactory.fromNodeJSReadable(response.body, {
etag: response.headers.get('ETag') ?? undefined,
lastModifiedAt: parseLastModified(
response.headers.get('Last-Modified'),
),
});
}
let message = `${url} could not be read as ${ghUrl}, ${response.status} ${response.statusText}`;
if (response.status === 404) {
throw new NotFoundError(message);
}
// GitHub returns a 403 response with a couple of headers indicating rate
// limit status. See more in the GitHub docs:
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
if (
response.status === 403 &&
response.headers.get('X-RateLimit-Remaining') === '0'
) {
message += ' (rate limit exceeded)';
}
throw new Error(message);
return ReadUrlResponseFactory.fromNodeJSReadable(response.body, {
etag: response.headers.get('ETag') ?? undefined,
lastModifiedAt: parseLastModified(response.headers.get('Last-Modified')),
});
}
async readTree(
@@ -350,10 +320,26 @@ export class GithubUrlReader implements UrlReader {
const response = await fetch(urlAsString, init);
if (!response.ok) {
const message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`;
let message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`;
if (response.status === 304) {
throw new NotModifiedError();
}
if (response.status === 404) {
throw new NotFoundError(message);
}
// GitHub returns a 403 response with a couple of headers indicating rate
// limit status. See more in the GitHub docs:
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
if (
response.status === 403 &&
response.headers.get('X-RateLimit-Remaining') === '0'
) {
message += ' (rate limit exceeded)';
}
throw new Error(message);
}
@@ -63,6 +63,22 @@ describe('Git', () => {
});
});
describe('remove', () => {
it('should call isomorphic-git remove with the correct arguments', async () => {
const git = Git.fromAuth({});
const dir = 'mockdirectory';
const filepath = 'mockfile/path';
await git.remove({ dir, filepath });
expect(isomorphic.remove).toHaveBeenCalledWith({
fs,
dir,
filepath,
});
});
});
describe('deleteRemote', () => {
it('should call isomorphic-git with the correct arguments', async () => {
const git = Git.fromAuth({});
+9
View File
@@ -300,6 +300,15 @@ export class Git {
return git.readCommit({ fs, dir, oid: sha });
}
/** https://isomorphic-git.org/docs/en/remove */
async remove(options: { dir: string; filepath: string }): Promise<void> {
const { dir, filepath } = options;
this.config.logger?.info(
`Removing file from git index {dir=${dir},filepath=${filepath}}`,
);
return git.remove({ fs, dir, filepath });
}
/** https://isomorphic-git.org/docs/en/resolveRef */
async resolveRef(options: { dir: string; ref: string }): Promise<string> {
const { dir, ref } = options;
+20
View File
@@ -1,5 +1,25 @@
# @backstage/backend-defaults
## 0.2.9
### Patch Changes
- 516fd3e: Updated README to reflect release status
- Updated dependencies
- @backstage/backend-common@0.20.1
- @backstage/backend-plugin-api@0.6.9
- @backstage/backend-app-api@0.5.10
## 0.2.9-next.2
### Patch Changes
- 516fd3e: Updated README to reflect release status
- Updated dependencies
- @backstage/backend-plugin-api@0.6.9-next.2
- @backstage/backend-app-api@0.5.10-next.2
- @backstage/backend-common@0.20.1-next.2
## 0.2.9-next.1
### Patch Changes
-2
View File
@@ -1,7 +1,5 @@
# @backstage/backend-defaults
**This package is EXPERIMENTAL, we recommend against using it for production deployments**
This package provides the default implementations and setup for a standard Backstage backend app.
## Installation
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-defaults",
"description": "Backend defaults used by Backstage backend apps",
"version": "0.2.9-next.1",
"version": "0.2.9",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+12
View File
@@ -1,5 +1,17 @@
# @backstage/backend-dev-utils
## 0.1.3
### Patch Changes
- 516fd3e: Updated README to reflect release status
## 0.1.3-next.0
### Patch Changes
- 516fd3e: Updated README to reflect release status
## 0.1.2
### Patch Changes
-2
View File
@@ -1,7 +1,5 @@
# @backstage/backend-dev-utils
**This package is EXPERIMENTAL, but we encourage use of it to add support for the new backend system in your own plugins**
This package helps set up local development environments for Backstage backend packages.
## Installation
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/backend-dev-utils",
"version": "0.1.2",
"version": "0.1.3",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -1,4 +1,48 @@
# @backstage/backend-plugin-manager
# @backstage/backend-dynamic-feature-service
## 0.1.0
### Minor Changes
- eb81f42: New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application.
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.20.1
- @backstage/cli-node@0.2.2
- @backstage/plugin-events-backend@0.2.18
- @backstage/backend-plugin-api@0.6.9
- @backstage/plugin-permission-common@0.7.12
- @backstage/plugin-permission-node@0.7.20
- @backstage/plugin-catalog-backend@1.16.1
- @backstage/backend-tasks@0.5.14
- @backstage/plugin-auth-node@0.4.3
- @backstage/plugin-scaffolder-node@0.2.10
- @backstage/plugin-search-backend-node@1.2.13
- @backstage/cli-common@0.1.13
- @backstage/config@1.1.1
- @backstage/errors@1.2.3
- @backstage/types@1.1.1
- @backstage/plugin-events-node@0.2.18
- @backstage/plugin-search-common@1.2.10
## 0.0.5-next.2
### Patch Changes
- Updated dependencies
- @backstage/backend-plugin-api@0.6.9-next.2
- @backstage/backend-common@0.20.1-next.2
- @backstage/plugin-auth-node@0.4.3-next.2
- @backstage/plugin-catalog-backend@1.16.1-next.2
- @backstage/plugin-events-backend@0.2.18-next.2
- @backstage/plugin-events-node@0.2.18-next.2
- @backstage/plugin-permission-node@0.7.20-next.2
- @backstage/plugin-scaffolder-node@0.2.10-next.2
- @backstage/plugin-search-backend-node@1.2.13-next.2
- @backstage/backend-tasks@0.5.14-next.2
- @backstage/cli-node@0.2.2-next.0
## 0.0.5-next.1
@@ -1,10 +1,6 @@
# @backstage/backend-plugin-manager
# @backstage/backend-dynamic-feature-service
This package adds experimental support for **dynamic backend plugins**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390)
## Status
**This package is EXPERIMENTAL, and is subject to change according to the discussions and conclusions that happen around the RFC mentioned above.**
This package adds experimental support for **dynamic backend features (plugins and modules)**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390)
## Testing the backend dynamic plugins feature
@@ -12,9 +8,9 @@ In order to test the dynamic backend plugins feature provided by this package, e
## How it works
The backend plugin manager is a service that scans a configured root directory (`dynamicPlugins.rootDirectory` in the app config) for dynamic plugin packages, and loads them dynamically.
The dynamic plugin manager is a service that scans a configured root directory (`dynamicPlugins.rootDirectory` in the app config) for dynamic plugin packages, and loads them dynamically.
In the `backend-next` application, it can be enabled by adding the `backend-plugin-manager` as a dependency in the `package.json` and the following lines in the `src/index.ts` file:
In the `backend-next` application, it can be enabled by adding the `backend-dynamic-feature-service` as a dependency in the `package.json` and the following lines in the `src/index.ts` file:
```ts
const backend = createBackend();
@@ -36,9 +32,9 @@ Points 2 and 3 can be done by the `export-dynamic-plugin` CLI command used to pe
### About the `export-dynamic-plugin` command
The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of a `@backstage/cli` fork (`@dfatwork-pkgs/backstage-cli@0.22.9-next.6`), and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature.
The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of the `@janus-idp/cli` package, and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature.
However the `backend-plugin-manager` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary.
However the `backend-dynamic-feature-service` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary.
### About the support of the legacy backend system
@@ -49,4 +45,4 @@ This is why the API related to the old backend is already marked as deprecated.
### Future work
The current implementation of the backend plugin manager is a first step towards the final implementation of the dynamic backend plugins feature, which will be completed / simplified in future steps, as the status of the backstage codebase allows it.
The current implementation of the dynamic plugin manager is a first step towards the final implementation of the dynamic features loading, which will be completed / simplified in future steps, as the status of the backstage codebase allows it.
@@ -1,4 +1,4 @@
## API Report File for "@backstage/backend-plugin-manager"
## API Report File for "@backstage/backend-dynamic-feature-service"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-backend-dynamic-feature-service
title: '@backstage/backend-dynamic-feature-service'
description: Backstage backend service to handle dynamic features
spec:
lifecycle: experimental
type: backstage-node-library
owner: maintainers
@@ -1,8 +1,7 @@
{
"name": "@backstage/backend-plugin-manager",
"description": "Backstage plugin management backend",
"version": "0.0.5-next.1",
"private": true,
"name": "@backstage/backend-dynamic-feature-service",
"description": "Backstage dynamic feature service",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -47,7 +47,7 @@ import { PluginScanner } from '../scanner/plugin-scanner';
import { findPaths } from '@backstage/cli-common';
import { createMockDirectory } from '@backstage/backend-test-utils';
describe('backend-plugin-manager', () => {
describe('backend-dynamic-feature-service', () => {
const mockDir = createMockDirectory();
describe('loadPlugins', () => {

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