merge
@@ -0,0 +1,18 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
We've bumped the `@eslint-typescript` packages to the latest, which now add some additional rules that might cause lint failures.
|
||||
The main one which could become an issue is the [no-use-before-define](https://eslint.org/docs/rules/no-use-before-define) rule.
|
||||
|
||||
Every plugin and app has the ability to override these rules if you want to ignore them for now.
|
||||
|
||||
You can reset back to the default behaviour by using the following in your own `.eslint.js`
|
||||
|
||||
```js
|
||||
rules: {
|
||||
'no-use-before-define': 'off'
|
||||
}
|
||||
```
|
||||
|
||||
Because of the nature of this change, we're unable to provide a grace period for the update :(
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': patch
|
||||
---
|
||||
|
||||
Allow expand functionality to top panel product chart tooltip.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Replace `register-component` plugin with new `catalog-import` plugin
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Fix HTTPS certificate generation and add new config switch, enabling it simply by setting `backend.https = true`. Also introduces caching of generated certificates in order to avoid having to add a browser override every time the backend is restarted.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Add `--lax` option to `config:print` and `config:check`, which causes all environment variables to be assumed to be set.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Added support for environment variable substitutions in string configuration values using a `${VAR}` placeholder. All environment variables must be available, or the entire expression will be evaluated to `undefined`. To escape a substitution, use `$${...}`, which will end up as `${...}`.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
baseUrl: https://${BASE_HOST}
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Improve error reporting for plugin misconfiguration.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Use .text instead of .json for ALB key response
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/techdocs-common': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Moving the Git actions to isomorphic-git instead of the node binding version of nodegit
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/config-loader': minor
|
||||
---
|
||||
|
||||
Removed support for the deprecated `$data` placeholder.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Tweaked development log formatter to include extra fields at the end of each log line
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Add processor for ingesting AWS accounts from AWS Organizations
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Provide support for on-prem azure devops
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
Add rate limiter for concurrent execution of file uploads in AWS and Google publishers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/config-loader': minor
|
||||
---
|
||||
|
||||
Enable further processing of configuration files included using the `$include` placeholder. Meaning that for example for example `$env` includes will be processed as usual in included files.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Updated example data in `README`.
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
* @backstage/maintainers
|
||||
/docs/features/techdocs @backstage/techdocs-core
|
||||
/docs/features/search @backstage/techdocs-core
|
||||
/plugins/cost-insights @backstage/silver-lining
|
||||
/plugins/cloudbuild @trivago/ebarrios
|
||||
/plugins/search @backstage/techdocs-core
|
||||
@@ -13,3 +14,4 @@
|
||||
/plugins/techdocs-backend @backstage/techdocs-core
|
||||
/packages/techdocs-common @backstage/techdocs-core
|
||||
/.changeset/cost-insights-* @backstage/silver-lining
|
||||
/.changeset/techdocs-* @backstage/techdocs-core
|
||||
|
||||
@@ -8,6 +8,8 @@ apis
|
||||
args
|
||||
asciidoc
|
||||
async
|
||||
Autoscaling
|
||||
autoscaling
|
||||
Avro
|
||||
backrub
|
||||
Balachandran
|
||||
@@ -36,6 +38,7 @@ Codecov
|
||||
codehilite
|
||||
Codehilite
|
||||
codeowners
|
||||
composability
|
||||
composable
|
||||
config
|
||||
Config
|
||||
@@ -63,11 +66,13 @@ Docusaurus
|
||||
Dominik
|
||||
dtuite
|
||||
dzolotusky
|
||||
eg
|
||||
Ek
|
||||
etag
|
||||
env
|
||||
Env
|
||||
esbuild
|
||||
eslint
|
||||
Expedia
|
||||
facto
|
||||
failover
|
||||
Figma
|
||||
@@ -75,21 +80,23 @@ Firekube
|
||||
Fiverr
|
||||
freben
|
||||
Fredrik
|
||||
github
|
||||
Georgoulas
|
||||
gitbeaker
|
||||
GitHub
|
||||
gitlab
|
||||
GitLab
|
||||
Grafana
|
||||
GraphQL
|
||||
graphql
|
||||
graphviz
|
||||
Gustavsson
|
||||
Hackathons
|
||||
haproxy
|
||||
Henneke
|
||||
heroku
|
||||
Heroku
|
||||
horizontalpodautoscalers
|
||||
Hostname
|
||||
hotspots
|
||||
html
|
||||
http
|
||||
https
|
||||
Iain
|
||||
@@ -98,8 +105,8 @@ incentivised
|
||||
inlined
|
||||
inlinehilite
|
||||
interop
|
||||
javascript
|
||||
Javascript
|
||||
Ioannis
|
||||
JavaScript
|
||||
jq
|
||||
js
|
||||
json
|
||||
@@ -108,9 +115,11 @@ Kaewkasi
|
||||
Knex
|
||||
kubectl
|
||||
kubernetes
|
||||
Kumar
|
||||
learnings
|
||||
lerna
|
||||
Lerna
|
||||
Luxon
|
||||
magiclink
|
||||
mailto
|
||||
maintainership
|
||||
@@ -120,6 +129,7 @@ microsite
|
||||
middleware
|
||||
minikube
|
||||
Minikube
|
||||
misconfiguration
|
||||
misgendering
|
||||
mkdocs
|
||||
Mkdocs
|
||||
@@ -138,10 +148,12 @@ Niklas
|
||||
nodegit
|
||||
nohoist
|
||||
nonces
|
||||
noop
|
||||
npm
|
||||
nvarchar
|
||||
nvm
|
||||
oauth
|
||||
Oauth
|
||||
OAuth
|
||||
octokit
|
||||
oidc
|
||||
Okta
|
||||
Oldsberg
|
||||
@@ -160,7 +172,6 @@ prebaked
|
||||
preconfigured
|
||||
prepack
|
||||
Preprarer
|
||||
Prerequisities
|
||||
productional
|
||||
Protobuf
|
||||
proxying
|
||||
@@ -182,6 +193,8 @@ rollbar
|
||||
Rollbar
|
||||
Rollup
|
||||
Rosaceae
|
||||
routable
|
||||
Routable
|
||||
rst
|
||||
rsync
|
||||
rugvip
|
||||
@@ -194,7 +207,7 @@ semlas
|
||||
semver
|
||||
Serverless
|
||||
Sinon
|
||||
smartsymobls
|
||||
Sneha
|
||||
Snyk
|
||||
sourcemaps
|
||||
sparklines
|
||||
@@ -221,7 +234,6 @@ Templater
|
||||
templaters
|
||||
Templaters
|
||||
Thauer
|
||||
theres
|
||||
toc
|
||||
tolerations
|
||||
Tolerations
|
||||
@@ -234,11 +246,13 @@ transpiled
|
||||
transpilation
|
||||
Tuite
|
||||
ui
|
||||
unmanaged
|
||||
untracked
|
||||
upvote
|
||||
url
|
||||
utils
|
||||
validators
|
||||
varchar
|
||||
Voi
|
||||
Wealthsimple
|
||||
Weaveworks
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: FOSSA
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
|
||||
# We use this to modify the generated .fossa.yml
|
||||
- name: Install yq
|
||||
run: sudo snap install yq
|
||||
|
||||
- name: Install Fossa
|
||||
run: "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash"
|
||||
|
||||
- name: Configure Fossa
|
||||
# The --option flag for fossa init does not work yet, see https://github.com/fossas/fossa-cli/issues/614
|
||||
run: |
|
||||
fossa init
|
||||
yq eval -i '.analyze.modules[].options.strategy = "yarn-list"' .fossa.yml
|
||||
|
||||
# This deletes entries for template and example packages found within packages and plugins
|
||||
# Seems like yq has a bug that causes only a subset of all matches to be deleted each run
|
||||
yq eval -i 'del(.analyze.modules[] | select(.path == "*/*/**"))' .fossa.yml
|
||||
yq eval -i 'del(.analyze.modules[] | select(.path == "*/*/**"))' .fossa.yml
|
||||
yq eval -i 'del(.analyze.modules[] | select(.path == "*/*/**"))' .fossa.yml
|
||||
yq eval -i 'del(.analyze.modules[] | select(.path == "*/*/**"))' .fossa.yml
|
||||
yq eval -i 'del(.analyze.modules[] | select(.path == "*/*/**"))' .fossa.yml
|
||||
|
||||
- name: Show config
|
||||
run: cat .fossa.yml
|
||||
|
||||
- name: Fossa Analyze
|
||||
env:
|
||||
# FOSSA Push-Only API Token
|
||||
FOSSA_API_KEY: 9ee7e8893660832a7387dcc32377fb61
|
||||
run: fossa analyze --branch "$GITHUB_REF"
|
||||
@@ -8,6 +8,9 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
needs_release: ${{ steps.release_check.outputs.needs_release }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x]
|
||||
@@ -47,6 +50,15 @@ jobs:
|
||||
run: yarn install --frozen-lockfile
|
||||
# End of yarn setup
|
||||
|
||||
- name: Fetch previous commit for release check
|
||||
run: git fetch origin '${{ github.event.before }}'
|
||||
|
||||
- name: Check if release
|
||||
id: release_check
|
||||
run: node scripts/check-if-release.js
|
||||
env:
|
||||
COMMIT_SHA_BEFORE: '${{ github.event.before }}'
|
||||
|
||||
- name: validate config
|
||||
run: yarn backstage-cli config:check
|
||||
|
||||
@@ -82,9 +94,10 @@ jobs:
|
||||
# We can't re-use the output from the above step, but we'll have a guaranteed node_modules cache and
|
||||
# only run the build steps that are necessary for publishing
|
||||
release:
|
||||
if: ${{ endsWith(github.event.head_commit.message, 'from backstage/changeset-release/master\n\nVersion Packages') }}
|
||||
needs: build
|
||||
|
||||
if: needs.build.outputs.needs_release == 'true'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x]
|
||||
node-version: [14.x]
|
||||
|
||||
env:
|
||||
CI: true
|
||||
@@ -27,6 +27,9 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: verify doc links
|
||||
run: node scripts/verify-links.js
|
||||
|
||||
# Skip caching of microsite dependencies, it keeps the global cache size
|
||||
# smaller, which make Windows builds a lot faster for the rest of the project.
|
||||
- name: yarn install
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
node-version: [14.x]
|
||||
|
||||
env:
|
||||
CI: true
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: ls microsite/build/backstage && ls microsite/build/backstage/storybook
|
||||
|
||||
- name: Deploy both microsite and storybook to gh-pages
|
||||
uses: JamesIves/github-pages-deploy-action@3.4.2
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
|
||||
@@ -55,6 +55,7 @@ jobs:
|
||||
|
||||
- name: tsc
|
||||
run: yarn tsc
|
||||
|
||||
- name: build
|
||||
run: yarn build
|
||||
|
||||
|
||||
@@ -9,17 +9,17 @@ on:
|
||||
pull_request:
|
||||
types: [opened, reopened, labeled, edited]
|
||||
|
||||
env:
|
||||
MY_GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
|
||||
jobs:
|
||||
assign_issue_or_pr_to_project:
|
||||
runs-on: ubuntu-latest
|
||||
name: Triage
|
||||
env:
|
||||
MY_GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
steps:
|
||||
- name: Assign new issue to Incoming based on its title.
|
||||
uses: srggrs/assign-one-project-github-action@1.2.0
|
||||
if: |
|
||||
env.MY_GITHUB_TOKEN != null &&
|
||||
contains(github.event.issue.title, 'TechDocs') ||
|
||||
contains(github.event.issue.title, 'techdocs') ||
|
||||
contains(github.event.issue.title, 'Techdocs')
|
||||
@@ -30,6 +30,7 @@ jobs:
|
||||
- name: Assign new issue to Incoming based on its label.
|
||||
uses: srggrs/assign-one-project-github-action@1.2.0
|
||||
if: |
|
||||
env.MY_GITHUB_TOKEN != null &&
|
||||
contains(github.event.issue.labels.*.name, 'docs-like-code')
|
||||
with:
|
||||
project: 'https://github.com/orgs/backstage/projects/1'
|
||||
@@ -38,6 +39,7 @@ jobs:
|
||||
- name: Assign new PR to Incoming based on its title.
|
||||
uses: srggrs/assign-one-project-github-action@1.2.0
|
||||
if: |
|
||||
env.MY_GITHUB_TOKEN != null &&
|
||||
contains(github.event.pull_request.title, 'TechDocs') ||
|
||||
contains(github.event.pull_request.title, 'techdocs') ||
|
||||
contains(github.event.pull_request.title, 'Techdocs')
|
||||
@@ -48,6 +50,7 @@ jobs:
|
||||
- name: Assign new PR to Incoming based on its label.
|
||||
uses: srggrs/assign-one-project-github-action@1.2.0
|
||||
if: |
|
||||
env.MY_GITHUB_TOKEN != null &&
|
||||
contains(github.event.pull_request.labels.*.name, 'docs-like-code')
|
||||
with:
|
||||
project: 'https://github.com/orgs/backstage/projects/1'
|
||||
|
||||
@@ -130,3 +130,6 @@ site
|
||||
|
||||
# Local configuration files
|
||||
*.local.yaml
|
||||
|
||||
# Sensitive credentials
|
||||
*-credentials.yaml
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
| Organization | Contact | Description of Use |
|
||||
| -------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
|
||||
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
|
||||
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
|
||||
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
|
||||
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
|
||||
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
|
||||
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
|
||||
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
|
||||
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
|
||||
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
|
||||
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
|
||||
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
|
||||
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
|
||||
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
|
||||
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
|
||||
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
|
||||
| Organization | Contact | Description of Use |
|
||||
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
|
||||
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
|
||||
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
|
||||
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
|
||||
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
|
||||
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
|
||||
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
|
||||
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
|
||||
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
|
||||
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
|
||||
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
|
||||
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
|
||||
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
|
||||
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
|
||||
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
|
||||
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
|
||||
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo) | EG Common Developer Toolkit |
|
||||
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
|
||||
|
||||
@@ -18,7 +18,7 @@ Harassment includes, but is not limited to:
|
||||
- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation
|
||||
- Unwelcome comments regarding a person’s lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment
|
||||
- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle
|
||||
- Physical contact and simulated physical contact (eg, textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop
|
||||
- Physical contact and simulated physical contact (e.g., textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop
|
||||
- Threats of violence, both physical and psychological
|
||||
- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm
|
||||
- Deliberate intimidation
|
||||
|
||||
@@ -10,13 +10,9 @@
|
||||
[](https://codecov.io/gh/backstage/backstage)
|
||||
[](https://github.com/backstage/backstage/releases)
|
||||
|
||||
> We recently moved from `spotify/backstage`, update your remotes!
|
||||
>
|
||||
> `git remote set-url origin git@github.com:backstage/backstage.git`
|
||||
|
||||
## What is Backstage?
|
||||
|
||||
[Backstage](https://backstage.io/) is an open platform for building developer portals. Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure. So your product teams can ship high-quality code quickly — without compromising autonomy.
|
||||
[Backstage](https://backstage.io/) is an open platform for building developer portals. Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure and enables your product teams to ship high-quality code quickly — without compromising autonomy.
|
||||
|
||||
Backstage unifies all your infrastructure tooling, services, and documentation to create a streamlined development environment from end to end.
|
||||
|
||||
@@ -43,7 +39,7 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
|
||||
|
||||
- [Main documentation](https://backstage.io/docs)
|
||||
- [Service Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview)
|
||||
- [Architecture](https://backstage.io/docs/overview/architecture-terminology) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview))
|
||||
- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview))
|
||||
- [Designing for Backstage](https://backstage.io/docs/dls/design)
|
||||
- [Storybook - UI components](https://backstage.io/storybook)
|
||||
|
||||
@@ -61,6 +57,6 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2020 © Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage
|
||||
Copyright 2020-2021 © Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage
|
||||
|
||||
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
@@ -16,6 +16,10 @@ backend:
|
||||
credentials: true
|
||||
csp:
|
||||
connect-src: ["'self'", 'http:', 'https:']
|
||||
reading:
|
||||
allow:
|
||||
- host: example.com
|
||||
- host: '*.mozilla.org'
|
||||
# workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir
|
||||
|
||||
# See README.md in the proxy-backend plugin for information on the configuration format
|
||||
@@ -76,7 +80,7 @@ techdocs:
|
||||
generators:
|
||||
techdocs: 'docker' # Alternatives - 'local'
|
||||
publisher:
|
||||
type: 'local' # Alternatives - 'googleGcs'. Read documentation for using alternatives.
|
||||
type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives.
|
||||
|
||||
sentry:
|
||||
organization: my-company
|
||||
@@ -127,7 +131,16 @@ integrations:
|
||||
|
||||
catalog:
|
||||
rules:
|
||||
- allow: [Component, API, Group, User, Template, Location]
|
||||
- allow:
|
||||
- Component
|
||||
- API
|
||||
- Resource
|
||||
- Group
|
||||
- User
|
||||
- Template
|
||||
- System
|
||||
- Domain
|
||||
- Location
|
||||
|
||||
processors:
|
||||
githubOrg:
|
||||
@@ -172,24 +185,46 @@ catalog:
|
||||
# groupFilter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
|
||||
|
||||
locations:
|
||||
# Add a location here to ingest it, for example from an URL:
|
||||
#
|
||||
# - type: url
|
||||
# target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-components.yaml
|
||||
#
|
||||
# For local development you can use a file location instead:
|
||||
#
|
||||
# - type: file
|
||||
# target: ../catalog-model/examples/all-components.yaml
|
||||
#
|
||||
# File locations are relative to the current working directory of the
|
||||
# backend, for example packages/backend/.
|
||||
|
||||
# Backstage example components
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-components.yaml
|
||||
- type: file
|
||||
target: ../catalog-model/examples/all-components.yaml
|
||||
# Example component for github-actions
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/plugins/github-actions/examples/sample.yaml
|
||||
# Example component for techdocs
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/examples/documented-component/documented-component.yaml
|
||||
- type: file
|
||||
target: ../../plugins/github-actions/examples/sample.yaml
|
||||
# Example component for TechDocs
|
||||
- type: file
|
||||
target: ../../plugins/techdocs-backend/examples/documented-component/catalog-info.yaml
|
||||
# Backstage example APIs
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-apis.yaml
|
||||
- type: file
|
||||
target: ../catalog-model/examples/all-apis.yaml
|
||||
# Backstage example resources
|
||||
- type: file
|
||||
target: ../catalog-model/examples/all-resources.yaml
|
||||
# Backstage example systems
|
||||
- type: file
|
||||
target: ../catalog-model/examples/all-systems.yaml
|
||||
# Backstage example domains
|
||||
- type: file
|
||||
target: ../catalog-model/examples/all-domains.yaml
|
||||
# Backstage example templates
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml
|
||||
- type: file
|
||||
target: ../../plugins/scaffolder-backend/sample-templates/all-templates.yaml
|
||||
# Backstage example groups and users
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml
|
||||
- type: file
|
||||
target: ../catalog-model/examples/acme-corp.yaml
|
||||
|
||||
scaffolder:
|
||||
github:
|
||||
@@ -206,6 +241,14 @@ scaffolder:
|
||||
api:
|
||||
token:
|
||||
$env: AZURE_TOKEN
|
||||
bitbucket:
|
||||
api:
|
||||
host: https://bitbucket.org
|
||||
username:
|
||||
$env: BITBUCKET_USERNAME
|
||||
token:
|
||||
$env: BITBUCKET_TOKEN
|
||||
|
||||
auth:
|
||||
environment: development
|
||||
### Providing an auth.session.secret will enable session support in the auth-backend
|
||||
@@ -329,3 +372,8 @@ homepage:
|
||||
timezone: 'Asia/Tokyo'
|
||||
pagerduty:
|
||||
eventsBaseUrl: 'https://events.pagerduty.com/v2'
|
||||
|
||||
kafka:
|
||||
clientId: backstage
|
||||
brokers:
|
||||
- localhost:9092
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
Backstage is an open-source developer portal that puts the developer experience first.
|
||||
annotations:
|
||||
github.com/project-slug: backstage/backstage
|
||||
backstage.io/techdocs-ref: github:https://github.com/backstage/backstage.git
|
||||
backstage.io/techdocs-ref: url:https://github.com/backstage/backstage
|
||||
lighthouse.com/website-url: https://backstage.io
|
||||
spec:
|
||||
type: library
|
||||
|
||||
@@ -8,8 +8,6 @@ FROM nginx:mainline
|
||||
# This dockerfile requires the app to be built on the host first, as it
|
||||
# simply copies in the build output into the image.
|
||||
|
||||
# The safest way to build this image is to use `yarn docker-build:app`
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY packages/app/dist /usr/share/nginx/html
|
||||
@@ -0,0 +1,52 @@
|
||||
# Authenticate API requests
|
||||
|
||||
The Backstage backend APIs are by default available without authentication. To avoid evil-doers from accessing or modifying data, one might use a network protection mechanism such as a firewall or an authenticating reverse proxy. For Backstage instances that are available on the Internet one can instead use the experimental IdentityClient as outlined below.
|
||||
|
||||
API requests from frontend plugins include an authorization header with a Backstage identity token acquired when the user logs in. By adding a middleware that verifies said token to be valid and signed by Backstage, non-authenticated requests can be blocked with a 401 Unauthorized response.
|
||||
|
||||
Note that this means Backstage will stop working for guests, as no token is issued for them.
|
||||
|
||||
Caveat: as of writing this, Backstage does not refresh the identity token so eventually users will get a 401 response on API calls (not on loading the web page as only the API calls are authenticated) and have to logout/login again to get a new token.
|
||||
|
||||
```typescript
|
||||
// packages/backend/src/index.ts from a create-app deployment
|
||||
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { IdentityClient } from '@backstage/plugin-auth-backend';
|
||||
|
||||
// ...
|
||||
|
||||
async function main() {
|
||||
// ...
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const identity = new IdentityClient({
|
||||
discovery,
|
||||
issuer: await discovery.getExternalBaseUrl('auth'),
|
||||
});
|
||||
const authMiddleware = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
try {
|
||||
const token = IdentityClient.getBearerToken(req.headers.authorization);
|
||||
req.user = await identity.authenticate(token);
|
||||
next();
|
||||
} catch (error) {
|
||||
res.status(401).send(`Unauthorized`);
|
||||
}
|
||||
};
|
||||
|
||||
const apiRouter = Router();
|
||||
// The auth route must be publically available as it is used during login
|
||||
apiRouter.use('/auth', await auth(authEnv));
|
||||
// Only authenticated requests are allowed to the routes below
|
||||
apiRouter.use('/catalog', authMiddleware, await catalog(catalogEnv));
|
||||
apiRouter.use('/techdocs', authMiddleware, await techdocs(techdocsEnv));
|
||||
apiRouter.use('/proxy', authMiddleware, await proxy(proxyEnv));
|
||||
apiRouter.use(authMiddleware, notFoundHandler());
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
HeaderLabel,
|
||||
SupportButton,
|
||||
identityApiRef,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { useApi } from '@backstage/core-api';
|
||||
import ExampleFetchComponent from '../ExampleFetchComponent';
|
||||
|
||||
const ExampleComponent = () => {
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
TableColumn,
|
||||
Progress,
|
||||
githubAuthApiRef,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { useApi } from '@backstage/core-api';
|
||||
import { graphql } from '@octokit/graphql';
|
||||
|
||||
const query = `{
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: adrs-adr000
|
||||
title: ADR000: [TITLE]
|
||||
description: Architecture Decision Record (ADR) for [TITLE] [DESCRIPTION]
|
||||
---
|
||||
|
||||
# ADR000: [title]
|
||||
|
||||
<!-- These documents have names that are short noun phrases. For example, "ADR001: Deployment on Ruby on Rails 3.0.10" or "ADR009: LDAP for Multitenant Integration" -->
|
||||
|
||||
## Context
|
||||
|
||||
<!--
|
||||
This section describes the forces at play, including technological, political, social, and project local. These forces are probably in tension, and should be called out as such. The language in this section is value-neutral. It is simply describing facts. -->
|
||||
|
||||
## Decision
|
||||
|
||||
<!-- This section describes our response to these forces. It is stated in full sentences, with active voice. "We will ..." -->
|
||||
|
||||
## Consequences
|
||||
|
||||
<!-- This section describes the resulting context, after applying the decision. All consequences should be listed here, not just the "positive" ones. A particular decision may have positive, negative, and neutral consequences, but all of them affect the team and project in the future. -->
|
||||
|
||||
<!-- This template is taken from a blog post by Michael Nygard http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions -->
|
||||
@@ -4,12 +4,16 @@ title: ADR001: Architecture Decision Record (ADR) log
|
||||
description: Architecture Decision Record (ADR) logs as a reference point for the team
|
||||
---
|
||||
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-04-26 | Open |
|
||||
## Decision
|
||||
|
||||
## Decision: A decision was made to store ADRs in a log in the project repository
|
||||
A decision was made to store ADRs in a log in the project repository
|
||||
|
||||
## Discussion: There is a need to store big decisions made in a log as a reference point for the team, help with onboarding new members and give context to others interested in the project.
|
||||
## Discussion
|
||||
|
||||
## Risks: People stop adding ADRs to the log and context gets lost
|
||||
There is a need to store big decisions made in a log as a reference point for
|
||||
the team, help with onboarding new members and give context to others interested
|
||||
in the project.
|
||||
|
||||
## Risks
|
||||
|
||||
People stop adding ADRs to the log and context gets lost
|
||||
|
||||
@@ -4,10 +4,6 @@ title: ADR002: Default Software Catalog File Format
|
||||
description: Architecture Decision Record (ADR) log on Default Software Catalog File Format
|
||||
---
|
||||
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-05-17 | Open |
|
||||
|
||||
## Background
|
||||
|
||||
Backstage comes with a software catalog functionality, that you can use to track
|
||||
|
||||
@@ -4,10 +4,6 @@ title: ADR003: Avoid Default Exports and Prefer Named Exports
|
||||
description: Architecture Decision Record (ADR) log on Avoid Default Exports and Prefer Named Exports
|
||||
---
|
||||
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-05-19 | Open |
|
||||
|
||||
## Context
|
||||
|
||||
When CommonJS was the primary authoring format, the best practice was to export
|
||||
|
||||
@@ -4,10 +4,6 @@ title: ADR004: Module Export Structure
|
||||
description: Architecture Decision Record (ADR) log on Module Export Structure
|
||||
---
|
||||
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-05-27 | Open |
|
||||
|
||||
## Context
|
||||
|
||||
With a growing number of exports of packages like `@backstage/core`, it is
|
||||
|
||||
@@ -4,10 +4,6 @@ title: ADR005: Catalog Core Entities
|
||||
description: Architecture Decision Record (ADR) log on Catalog Core Entities
|
||||
---
|
||||
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-05-29 | Open |
|
||||
|
||||
## Context
|
||||
|
||||
We want to standardize on a few core entities that we are tracking in the
|
||||
|
||||
@@ -43,6 +43,15 @@ const GoodComponent = ({ text, children }: GoodProps) => (
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
/* Or as a shorthand, if no specifc child type is required */
|
||||
type GoodProps = PropsWithChildren<{ text: string }>;
|
||||
const GoodComponent = ({ text, children }: GoodProps) => (
|
||||
<div>
|
||||
<div>{text}</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: adrs-adr010
|
||||
title: ADR010: Use the Luxon Date Library
|
||||
description: Architecture Decision Record (ADR) for Luxon Date Library
|
||||
---
|
||||
|
||||
# ADR010: Use the Luxon Date Library
|
||||
|
||||
## Context
|
||||
|
||||
Date formatting (e.g. `a day ago`) and calculations are common within Backstage.
|
||||
Some of these useful features are not supported by the standard JavaScript
|
||||
`Date` object. The popular [Moment.js](https://momentjs.com/) library has been
|
||||
commonly used to fill this gap but suffers from large bundle sizes and mutable
|
||||
state issues. On top of this, `momentjs` is
|
||||
[being sunset](https://momentjs.com/docs/#/-project-status/) and the project
|
||||
recommends using one of the more modern alternative libraries.
|
||||
|
||||
See
|
||||
[[RFC] Standardized Date & Time Library](https://github.com/backstage/backstage/issues/3401).
|
||||
|
||||
## Decision
|
||||
|
||||
We will use [Luxon](https://moment.github.io/luxon/index.html) as the standard
|
||||
date library within Backstage.
|
||||
|
||||
`Luxon` provides a similar feature set and API to `Moment.js`, but improves on
|
||||
its design through immutability and the usage of modern JavaScript APIs (e.g.
|
||||
`Intl`). This results in smaller bundle sizes while providing a full feature set
|
||||
and avoids the need for using additional libraries for common date & time tasks.
|
||||
|
||||
## Consequences
|
||||
|
||||
- All core packages and plugins within Backstage should use `Luxon` for any date
|
||||
manipulation or formatting that cannot be easily accomplished with the native
|
||||
JavaScript `Date` object.
|
||||
- Using a single date library avoids having to learn multiple library APIs
|
||||
- Having a single date library will reduce bundle sizes
|
||||
@@ -18,8 +18,9 @@ Records should be stored under the `architecture-decisions` directory.
|
||||
|
||||
### Creating an ADR
|
||||
|
||||
- Copy `0000-template.md` to `docs/architecture-decisions/0000-my-decision.md`
|
||||
(my-decision should be descriptive. Do not assign an ADR number.)
|
||||
- Copy `docs/architecture-decisions/adr000-template.md` to
|
||||
`docs/architecture-decisions/adr000-my-decision.md` (my-decision should be
|
||||
descriptive. Do not assign an ADR number.)
|
||||
- Fill in the ADR following the guidelines in the template
|
||||
- Submit a pull request
|
||||
- Address and integrate feedback from the community
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="789px" height="766px" viewBox="-0.5 -0.5 789 766" content="<mxfile host="bd2205bb-07f8-4b61-b1c1-5174fe4ebe37" modified="2021-01-14T13:46:42.842Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.52.0 Chrome/83.0.4103.122 Electron/9.3.5 Safari/537.36" etag="jW9IV2PM6529z9FP4d6-" version="13.10.0" type="embed"><diagram id="AOZgdlUmH_6GT6Gt5u4e" name="Page-1">7V1bc6M4Fv41rpp5CMVNAh4TJ5ntre7qbGdqdvqRYMWmG4MXcGLvrx8JSYAuNtgG59JJV3VASALOd3R0zqcjMnGmy80febhafMlmKJnY5mwzca4ntu3ZPv6fFGxpAXQALZjn8YwWWU3Bffx/xApNVrqOZ6gQKpZZlpTxSiyMsjRFUSmUhXmePYvVHrNEvOsqnCOl4D4KE7X0v/GsXNBSH5hN+b9QPF/wO1smu/IQRj/nebZO2f0mtvNY/dDLy5D3xeoXi3CWPbeKnJuJM82zrKRHy80UJUS0XGy03e2Oq/Vz5ygt+zSALm3xFCZrxB+5erByy4XxvIhLdL8KI3L+jPGeOFeLcpngMwsfhsWKQvAYbxDu9uoxTpJplmR51dyxral5CXB5UebZT9S6YpoQAp+0yNKyVQ6m5B8uZ8+G8hJtdr6gVYsNayPKlqjMt7gKawACpnlME90goOfPDa6Wy9BYtDHlhSHTpXnddyNPfMBEukO8zjsXrwteUryepUgTzfBAZqdZXi6yeZaGyU1TelWNTiLJaxOfNXU+Z9mKyfwHKssts0rhusxERNAmLv8mzQ0PsNPvrUvXG9Z1dbJlJ0UZ5uUlMU24IM1SxMtuY/J6tEE64zWiJCyKOKKFrIp1AshELPshxlLM1nnEanlMcfETzhGr5us1IUdJWMZPYvc6VFnTuyzGN641CHKjuuVzBxC7oI/AWjW6gSUVblvVVqRCsfs+ninfx5RUjfbYKF79jr100Q1+saFucaDOMtTXf20vp9HzZuluzOW/s23w14/igrsZ+2QuDvcuBJJ4nuLjBD2WI8hfM+gUSHrL37FcRf62P5b8gf3O1Vt2FF6DegONzGFCNHMWP+HDeVm9Oy16yOUSfFOh3nsdGTVU3AnxXUOHnqVBLxgNPJ1n/QGeatbEadlRcbP5yBRGnTcAcO7pRm2PzFpSZg7fLCwWFWbWyLZMHA9QI1Oos2TOADLtMSXjoHdFDqNtEmMlzu1uDX6g6v75oS6oA+2v6xJ3gzge1Gu3wGvTcwCB4TsiLhpggG84rgqND05Hxla1/XK1wgV3WJYVIXI5IU4xDJdE+pUV+patS1S9OntA+L91xsxTgcI8WrSLTJSgJRORdyX2ZBhG1fttXUwNm3etLZZ1Bku5FFUiRxjr8KGqQGwgCdQ4+i2bF+HnQRjPKwJVHIXJJbuwjGezKiBkkQO+DbiagGv90BV1hhWKRnhE5XEk30TVG8fWDGh7gPFsaygMt+K5cPiKlca+XSXreZxeUHW4IFdwzPoBoOS8i9OcZWpsss4/GQRC1Y/8Wi6wTPHQr7ArVDfktz9RtLjOInwJ929OwzJMsjluXp3elNHvwyHM3JK3jK/igro+YYcUF1Q37Q4x69rwEG+TCGJC2HMui8aE13R1y6oXnJ/nZVb7cg9Hlt7v1/RvZc3AqqELTrSD3/K8WotO0g6NU7bHhn/YbhFBS0LQ1oeXurE9hPnWhpeuo6B0RuqbHxPe2zQ4C65nvrHg823diJzQVpQ8J+dNu+qsocwHG65taht4tKxNbQPmcks0+alk98EcdSAGCI4XtBWls74V2JJitThttbVMKEJLsTZUcAr53tmX7XpiRztY/COIdj3borLv3MW54g4pc3bwwTmdm3dhAmX31Q56cs+j2T/HUgC/Z5OXeZPOCSGAcb5JwgILneJ6nyU5OwrDe3qEysj4AFsC2wuMoP3jCth7fJ5rY++cFXs1JFWx/4SRmOfYWGdkxH8Ot8QYfOC8Z1C7nmto3JpgJGi5ypzZg+HeSO1vMB8GdrsjrRX8Zn2+vYgvZAcILpLXw0e6Q3mMpUj0akz/hw/ftv/jjeP/KG6CvIYJLM+wRlrwd2XSjDlLu1wYuT5gQunnTMlvZpuB0c+XGsoFAi87niTv/qDRtCsfRhtt2PuH0lhRg6sZNc4oo+ZQRfel+NSC3l5Fl+sDb08mjNpa5jMss5eaqyGDPN4OsAVHjJnv0AXbNfzx9Ox9uUfbfJr/jC4cHW0mDaIO7ul1kU0StB7oO6PLKB4zo+tFfHpe1KsSMZQlrMhXlyQyxGq1Vrz8Zu9FvLIG6xZKtAoMgTzfDidj3Zr2MUw65bqxAEzSnbOTIX/D+NUZ5Rw/rQnS5lGNNUSALgmbSr5Yhakga44VkdAFDfzIorhn2KsN/l3JyCRh4wULBcnVatlBgflvfCVdLx8qEip7JLfhQSqOMtdJWbTwpw+yA/+3F6beVj8DWQTTFzTK185p5lhRqqfAcdYU8/4Z5k1k2zjf3wXf+6S49lyZ544m85xmxJzgV/feUABeFO1D4pwW3Ca0xeArCLwO0HcQDgftUWA1mg0Kp4RfQ6gJTec7+6KNJZgnHhUOta9AQ3Z2zl7MHSFzUz5/+K3KBzQp4S0d/15PatKMFxw8302z5QprRNp/XnvT+eJ1Oh3HHUBlVoJQ46fCAczUi05KRy3+SnSrPRTb+nq2TDkahgiaeh0a1yI50lYGx7fb2tVZ34L+oCbMU+OnO4xVnfGZPhTkF1/DkROJ/kT5krx9tYaLgcUTliZhjV4uFyhVr31D5TonpvIbd7w1o+dz+ICSiTavqNuPlh1y1a9OSPdXddZyS+9YnHiEtWLbn9l9J7XD29ZUait2mjHTsHzGF9brQPTsRKr/AgqdAkOm9rLHxwKdyurxQTdQaF4vI17efeobnfNsdiz0MElQks3zcElUoOVdCddabldXYls18903gd2rmgEt2czwPWLtuEyXlgwHiMtc3d6ol+VNTttdedw2mCFCXA++pDchBj3Hxjz16tO54x2iEuwdgzM6Gy5UnY1XEf4Alpgz2Lbq3YnNH+HPSxp/VzT+buDrkmLHioDAyxI14pcfajt1EC/XZbLeEhsDNGwMOBdpt4ffZz5gJ79vmWS8K95gtECzdUII/HfoCkoc/UnWAJq+IacFOLoNMCwSFeyBO4QOdMYBnToQ6FTgj5BlEV9n0XopWfdTFu2Gt+6D4ukEEp4Wl3B7r6qlggmGALNHVsZb3UN8WpDgBYYlBuuOG2jXVw1fs4sYKDlpR8Hjv5V44U1NobptKXAIj15x2YGt32YyQtYVf6tT5mZLZ5ix4LEMkM4yN7zfV2K5v6AynIVl+EsYbuBLnAw25Bq3XLdVwx+ASoC6bKQBpuGKjjNv0tmK6mTvvabvCVs3UCdlzQckRpqUoY5wGwDa/6xR9ZJ3eRahoojTeV8w1bSYIfl6KaWmxfNYmq+3DIozcA0QiEBrxvBY+zJgZ7bbcUB/wvP/5gPoAz85NtamOqhLyz0J5cNWWt6HNgz6gaAeX6odSxu8weftw7ThfUwC5/6w7lgzgNdJqB0Ebu2u8YIvYVp9dcJkRqBG+kFpUnt40xxV7j4h7r+hZfZUH68S4s4JcQDLFcDdx1idRnMOxaWfV8UUqAQO4PstzxAG8HjyvAzBcClDvRf1mgUBu3+i7uQofsA7lU4/anUPmKIW7f1qstoaQm3rLqKh8zGg3NFweyu9Tib5IONHlgXjBNU26WaDIvpJPT7nPeYZSW/al+X0K1kuV2IwgK1xgzQxrn94jItPm7+0QFWl+WsWzs0/</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<rect x="560" y="484" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="420" y="484" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<path d="M 664.5 595 L 664.5 705 L 595.54 705" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 590.29 705 L 597.29 701.5 L 595.54 705 L 597.29 708.5 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="420" y="110" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="420" y="299" width="280" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="560" y="110" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="90" y="469.25" width="110" height="90" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 108px; height: 1px; padding-top: 514px; margin-left: 92px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<div>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="92" y="518" fill="#5C5C5C" font-family="Helvetica" font-size="12px">
|
||||


|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="5" y="20" width="295" height="170" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 293px; height: 1px; padding-top: 105px; margin-left: 7px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<div>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="7" y="109" fill="#5C5C5C" font-family="Helvetica" font-size="12px">
|
||||


|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="20" y="50" width="260" height="130" fill="none" stroke="#006658" stroke-dasharray="3 3" pointer-events="all"/>
|
||||
<path d="M 530.83 665 C 530.83 656.72 543.89 650 560 650 C 567.74 650 575.16 651.58 580.63 654.39 C 586.1 657.21 589.17 661.02 589.17 665 L 589.17 720 C 589.17 723.98 586.1 727.79 580.63 730.61 C 575.16 733.42 567.74 735 560 735 C 543.89 735 530.83 728.28 530.83 720 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 589.17 665 C 589.17 668.98 586.1 672.79 580.63 675.61 C 575.16 678.42 567.74 680 560 680 C 543.89 680 530.83 673.28 530.83 665" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="0" y="0" width="320" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 10px; margin-left: 160px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
App Package: <Route path="/search" element={<... />} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="160" y="14" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
App Package: <Route path="/search" element={<... />}...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="415" y="90" width="210" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 100px; margin-left: 520px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
@backstage/plugin-search-backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="520" y="104" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
@backstage/plugin-search-backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="90" y="433.75" width="160" height="30" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 449px; margin-left: 92px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
Other Plugins
|
||||
<br/>
|
||||
(TechDocs, Catalog, Etc)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="92" y="452" fill="#5C5C5C" font-family="Helvetica" font-size="12px">
|
||||
Other Plugins...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="90" y="229.25" width="210" height="177.75" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 208px; height: 1px; padding-top: 318px; margin-left: 92px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<div>
|
||||
<font color="#ffffff" size="1">
|
||||
<br/>
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="92" y="322" fill="#5C5C5C" font-family="Helvetica" font-size="12px"></text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="80" y="209.25" width="160" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 219px; margin-left: 160px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
@backstage/plugin-search
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="160" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
@backstage/plugin-search
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 630 364.25 L 758 364.3 L 758 177.3 L 661.87 177.25" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 656.62 177.25 L 663.62 173.75 L 661.87 177.25 L 663.62 180.75 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="415" y="279" width="280" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 289px; margin-left: 555px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
Other Backend Plugin (TechDocs, Catalog, Etc)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="555" y="293" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Other Backend Plugin (TechDocs, Catalog, Etc)
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="445" y="745" width="230" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 755px; margin-left: 560px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
Search Engine (Elastic, Solr, SaaS, etc.)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="560" y="759" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Search Engine (Elastic, Solr, SaaS, et...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="415" y="459.5" width="190" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 470px; margin-left: 510px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
Search Engine Integration Layer
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="510" y="473" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Search Engine Integration Layer
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 458.13 178.25 L 400 178.3 L 400 559.8 L 443.63 559.77" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 463.38 178.25 L 456.38 181.76 L 458.13 178.25 L 456.38 174.76 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 448.88 559.77 L 441.88 563.27 L 443.63 559.77 L 441.88 556.27 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 655.5 151.75 L 780 151.8 L 780 555 L 690.87 555" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 685.62 555 L 692.62 551.5 L 690.87 555 L 692.62 558.5 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="80" y="60.5" width="190" height="10" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="30" y="60" width="40" height="70" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="80" y="90" width="190" height="65.5" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<rect x="229" y="160.5" width="40" height="10" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 166px; margin-left: 230px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font color="#ffffff">
|
||||
1 2 3
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="249" y="169" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
1 2 3
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="73" y="70.5" width="100" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 81px; margin-left: 123px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<span style="font-size: 7.2px ; text-align: left">
|
||||
X number of search results
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="123" y="84" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
X number of sear...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 220 313.37 L 220 330.63" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 220 308.12 L 223.5 315.12 L 220 313.37 L 216.5 315.12 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 220 335.88 L 216.5 328.88 L 220 330.63 L 223.5 328.88 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 187 257.5 L 36.1 257.5 L 36.12 179.61" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<rect x="187" y="241" width="66" height="66" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 64px; height: 1px; padding-top: 274px; margin-left: 188px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<span style="color: rgb(255 , 255 , 255) ; font-size: 9px ; text-align: left">
|
||||
Components
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="220" y="278" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Components
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 276.37 367 L 360 367 L 360 152.8 L 458.13 152.75" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 271.12 367 L 278.12 363.5 L 276.37 367 L 278.12 370.5 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 463.38 152.75 L 456.38 156.25 L 458.13 152.75 L 456.38 149.25 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 220px; margin-left: 351px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||
Pass Search
|
||||
<br/>
|
||||
Term and Filters
|
||||
<br/>
|
||||
and then
|
||||
<br/>
|
||||
Return Results
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="351" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
Pass Search...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 160 397 L 180 337 L 280 337 L 260 397 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 367px; margin-left: 161px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font color="#ffffff">
|
||||
Search API
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="220" y="371" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Search API
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="5" y="20" width="295" height="20" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<path d="M 110 516.25 L 36.1 516.3 L 36.12 180" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<rect x="110" y="483.25" width="66" height="66" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 64px; height: 1px; padding-top: 516px; margin-left: 111px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<span style="color: rgb(255 , 255 , 255) ; font-size: 9px ; text-align: left">
|
||||
Components
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="143" y="520" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Components
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 635 198.75 L 630 198.8 L 630 190" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 573.5 239.75 L 593.5 198.75 L 655.5 198.75 L 635.5 239.75 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 80px; height: 1px; padding-top: 219px; margin-left: 575px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 10px">
|
||||
Scheduler
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="615" y="223" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Scheduler
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="604.5" y="139" width="51" height="51" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 49px; height: 1px; padding-top: 165px; margin-left: 606px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 9px">
|
||||
Gather Documents
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="630" y="168" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Gather D...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 444.17 349.5 C 444.17 341.22 453.31 334.5 464.59 334.5 C 470.01 334.5 475.2 336.08 479.03 338.89 C 482.86 341.71 485.01 345.52 485.01 349.5 L 485.01 379 C 485.01 387.28 475.87 394 464.59 394 C 453.31 394 444.17 387.28 444.17 379 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 485.01 349.5 C 485.01 357.78 475.87 364.5 464.59 364.5 C 453.31 364.5 444.17 357.78 444.17 349.5" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 550 364.25 L 517.5 364.3 L 485.01 364.3" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<rect x="550" y="324.25" width="80" height="80" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 364px; margin-left: 551px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 11px">
|
||||
Collate Documents
|
||||
<br/>
|
||||
Or Metadata
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="590" y="368" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Collate Docum...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="464.5" y="140" width="51" height="51" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 49px; height: 1px; padding-top: 166px; margin-left: 466px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 9px">
|
||||
API Endpoint
|
||||
<br/>
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="490" y="169" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
API Endp...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="419.59" y="110" width="90" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 120px; margin-left: 465px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font style="font-size: 9px">
|
||||
Query Processing
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="465" y="123" fill="#FFFFFF" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
Query Processing
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="560" y="110" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 120px; margin-left: 600px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font style="font-size: 9px">
|
||||
Index Processing
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="600" y="123" fill="#FFFFFF" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
Index Processi...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="560" y="484" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 494px; margin-left: 600px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font style="font-size: 9px" color="#ffffff">
|
||||
Index Processing
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="600" y="497" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
Index Processi...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="420" y="484" width="90" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 494px; margin-left: 465px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font style="font-size: 9px" color="#ffffff">
|
||||
Query Processing
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="465" y="497" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
Query Processing
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="604.5" y="515" width="80" height="80" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 555px; margin-left: 606px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font color="#ffffff">
|
||||
<b>
|
||||
Manage Index
|
||||
</b>
|
||||
<br/>
|
||||
Create, Remove, Replace Documents and Indices
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="645" y="558" fill="#5C5C5C" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Manage Index...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 470.25 601.37 L 470.3 705 L 524.63 705" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 470.25 596.12 L 473.75 603.12 L 470.25 601.37 L 466.75 603.12 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 529.88 705 L 522.88 708.5 L 524.63 705 L 522.88 701.5 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="450" y="514" width="81" height="81" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 79px; height: 1px; padding-top: 555px; margin-left: 451px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font color="#ffffff">
|
||||
Compile and Execute Query from Term and Filters
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="491" y="557" fill="#5C5C5C" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Compile and Execut...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
<a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank">
|
||||
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||
Viewer does not support full SVG 1.1
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,144 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="605px" height="362px" viewBox="-0.5 -0.5 605 362" content="<mxfile host="046c5cfb-a3a2-464c-a595-f674d31136ed" modified="2020-12-26T01:33:35.255Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.52.1 Chrome/83.0.4103.122 Electron/9.3.5 Safari/537.36" etag="nIR1gVsObWk5MHRRKeB7" version="13.10.0" type="embed"><diagram id="fZcCmqQ9Q5JzR6r55YHy" name="Page-1">7VhNc5swEP01HJtBiA/7iI3dHtqT20lzlIUCajCishzb/fVdQBhkSOLWjtPJ9JJo367Qat/TImzh6Wr3UZIi/SJillmOHe8sHFmO43sI/pbAXgPBuAYSyeMasltgwX+xGkQNuuExW2ushpQQmeKFCVKR54wqAyNSiq0Zdi+y2AAKkrAesKAk66O3PFapRn3bbh2fGE9SvfS4cSwJfUik2OR6PcvBczQPZ7PavSLNs3T8OiWx2HYgPLPwVAqh6tFqN2VZWVqzbPMnvIe8JcvVKRM8nccjyTasSblKTO2bYmxTrtiiILS0t8C3hSepWmVgIRje8yybikxIsHORQ9BkraR4YA0INXC9YDKOwKNXY1Kx3ZMpo0MhQF9MrJiSewjRE5xRPUNLy3Frc9vy5Nu4xtIORdjXWyVaG8nhyW19YKBLNFwu1+9VR0iVikTkJPssRKFr8oMptdeyJhslzIqxHVffYWzr8V0Hj3YdR7RvjBwSrabceI151/W10yqrnReH5XFoqQFkzsv9Vf6aqEbi6FnqKlWzWM+s68Di3jk6ohFqJTaS6ijNiyIyYTrK9YbZliwjij+ajz+Lu6DHXZn+Qpu6PuYuzyAX/SPkDlHZp/1ydLpXohMPNC4/U2VDEpByl2f/50Y0jg/rirgQApBf7FonjBL9v3rKsgHCeMXzBoWslm2k/W3NZMdVr9x4j8RmKuuFprp+YIqmLxLZ7b2Ah6MojKZ6px0cRdjzgkNSA6z2OvLT7ddFRv9Fdr8Bo8DtN+Cxd4Ez7FyN9dsFBIeUAmtqmP3TaIeyqiNuDTr10R14i5KMJzmYFMgCmeFJSRKHS0qoHSsex+Uyg2Iy5Wbo6RXVgbEhDuz3tYFQXxvOJd7N7rW08ZXRNBJ0/a6awll3Mhd5R5eyAeJfrSl41yJ+Aeq2JxsKPJzTEt4J6X7whpyPXuKcHjbd0lqWazmOu9AJ2nCHtNE95EvZoIXION3//atBMliXLKuAku/yellnUrlPfyMUgueqqq83sbxjgQx+pg1egC/RG4Lxjdkd0Aj3lNKIx/hkcy8glPEbC8VsF/+l8pxUkBOcIBVv6Ov+z6UCZvs7S+Xr/JaFZ78B</diagram></mxfile>" style="background-color: rgb(241, 250, 238);">
|
||||
<defs/>
|
||||
<g>
|
||||
<rect x="0" y="0" width="603" height="360" fill="none" stroke="#457b9d" pointer-events="all"/>
|
||||
<path d="M 213 175 L 126 222" fill="none" stroke="#457b9d" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 387 175 L 474 222" fill="none" stroke="#457b9d" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<rect x="213" y="80" width="174" height="95" fill="#a8dadc" stroke="#457b9d" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 172px; height: 1px; padding-top: 128px; margin-left: 214px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #1D3557; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 16px">
|
||||
<b>
|
||||
Admin
|
||||
</b>
|
||||
User
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="300" y="131" fill="#1D3557" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Admin User
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="5" y="12" width="111" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 109px; height: 1px; padding-top: 22px; margin-left: 6px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #1D3557; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 16px">
|
||||
<b>
|
||||
AWS Account
|
||||
</b>
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="61" y="26" fill="#1D3557" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
AWS Account
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="387" y="222" width="174" height="95" fill="#a8dadc" stroke="#457b9d" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 172px; height: 1px; padding-top: 270px; margin-left: 388px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #1D3557; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 16px">
|
||||
<b>
|
||||
TechDocs
|
||||
</b>
|
||||
User
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="474" y="273" fill="#1D3557" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
TechDocs User
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="39" y="222" width="174" height="95" fill="#a8dadc" stroke="#457b9d" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 172px; height: 1px; padding-top: 270px; margin-left: 40px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #1D3557; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
<font style="font-size: 16px">
|
||||
<b>
|
||||
S3 Bucket
|
||||
</b>
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="126" y="273" fill="#1D3557" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
S3 Bucket
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="451.5" y="159" width="46" height="34" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 176px; margin-left: 475px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font color="#457b9d" style="font-size: 14px">
|
||||
User
|
||||
<br/>
|
||||
policy
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="475" y="180" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
User...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="99.5" y="159" width="53" height="34" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<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: 176px; margin-left: 126px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||
<font color="#457b9d" style="font-size: 14px">
|
||||
Bucket
|
||||
<br/>
|
||||
policy
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="126" y="180" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Bucket...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
<a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank">
|
||||
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||
Viewer does not support full SVG 1.1
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -61,6 +61,19 @@ If your authentication provider is any of the above mentioned providers, you can
|
||||
configure them by setting the right variables in `app-config.yaml` under the
|
||||
`auth` section.
|
||||
|
||||
### SAML
|
||||
|
||||
The SAML Provider is currently under development. Additional validation and
|
||||
profile handling is still required before use in production.
|
||||
|
||||
To configure the SAML Auth provider, look at the configuration parameters
|
||||
supported by
|
||||
[Passport-SAML](https://github.com/node-saml/passport-saml#config-parameter-details)
|
||||
under the `auth.providers.saml` key
|
||||
|
||||
For security reasons, validate that the response from the IdP is indeed signed
|
||||
by also providing the `cert` configuration.
|
||||
|
||||
### Configuration
|
||||
|
||||
Each authentication provider (except SAML) needs five parameters: an OAuth
|
||||
@@ -96,6 +109,11 @@ auth:
|
||||
development:
|
||||
clientId:
|
||||
$env:
|
||||
saml:
|
||||
entryPoint:
|
||||
$env: AUTH_SAML_ENTRY_POINT
|
||||
issuer:
|
||||
$env: AUTH_SAML_ISSUER
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
id: oauth
|
||||
title: OAuth and OpenID Connect
|
||||
description: This section describes how Backstage allows plugins to request
|
||||
OAuth Access Tokens and OpenID Connect ID Tokens on behalf of the user, to be
|
||||
used for auth to various third party APIs
|
||||
# prettier-ignore
|
||||
description: This section describes how Backstage allows plugins to request OAuth Access Tokens and OpenID Connect ID Tokens on behalf of the user, to be used for auth to various third party APIs
|
||||
---
|
||||
|
||||
This section describes how Backstage allows plugins to request OAuth Access
|
||||
|
||||
@@ -28,6 +28,7 @@ app:diff Diff an existing app with the creation template
|
||||
app:serve Serve an app for local development
|
||||
|
||||
backend:build Build a backend plugin
|
||||
backend:bundle Bundle the backend into a deployment archive
|
||||
backend:build-image Bundles the package into a docker image
|
||||
backend:dev Start local development server with HMR for the backend
|
||||
|
||||
@@ -166,7 +167,7 @@ Options:
|
||||
|
||||
## backend:build
|
||||
|
||||
Scope: `backend`, `backend-plugin`
|
||||
Scope: `backend-plugin`
|
||||
|
||||
This builds a backend package for publishing and use in production. The build
|
||||
output is written to `dist/`. Be sure to list any additional file that the
|
||||
@@ -180,6 +181,52 @@ Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## backend:bundle
|
||||
|
||||
Scope: `backend`
|
||||
|
||||
Bundle the backend and all of its local dependencies into a deployment archive.
|
||||
The archive is written to `dist/bundle.tar.gz`, and contains the packaged
|
||||
version of all dependencies of the target package, along with the target package
|
||||
itself. The layout of the packages in the archive is the same as the directory
|
||||
layout in the target monorepo, and the bundle also contains the root
|
||||
`package.json` and `yarn.lock`.
|
||||
|
||||
To use the bundle, extract it into a target directory, run
|
||||
`yarn install --production`, and then start the target backend package using for
|
||||
example `node package/backend`.
|
||||
|
||||
The `dist/bundle.tar.gz` is accompanied by a `dist/skeleton.tar.gz`, which has
|
||||
the same layout, but only contains `package.json` files and `yarn.lock`. This
|
||||
can be used to run a `yarn install` in environments that will benefit from the
|
||||
caching that this enables, such as Docker image builds. To use the skeleton
|
||||
archive, simply extract it first, run install, and then extract the main bundle.
|
||||
|
||||
The following is an example of a `Dockerfile` that can be used to package the
|
||||
output of `backstage-cli backend:bundle` into an image:
|
||||
|
||||
```Dockerfile
|
||||
FROM node:14-buster
|
||||
WORKDIR /app
|
||||
|
||||
ADD yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
|
||||
RUN yarn install --production --network-timeout 600000 && rm -rf "$(yarn cache dir)"
|
||||
|
||||
ADD packages/backend/dist/bundle.tar.gz app-config.yaml ./
|
||||
|
||||
CMD node packages/backend
|
||||
```
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:bundle [options]
|
||||
|
||||
Bundle the backend into a deployment archive
|
||||
|
||||
Options:
|
||||
--build-dependencies Build all local package dependencies before bundling the backend
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## backend:build-image
|
||||
|
||||
Scope: `backend`
|
||||
|
||||
@@ -36,6 +36,10 @@ export interface Config {
|
||||
* @visibility frontend
|
||||
*/
|
||||
baseUrl: string;
|
||||
|
||||
// Use @items.<name> to assign annotations to primitive array items
|
||||
/** @items.visibility frontend */
|
||||
myItems: string[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,8 +18,8 @@ allowing for customization.
|
||||
Configuration is stored in YAML files where the defaults are `app-config.yaml`
|
||||
and `app-config.local.yaml` for local overrides. Other sets of files can by
|
||||
loaded by passing `--config <path>` flags. The configuration files themselves
|
||||
contain plain YAML, but with support for loading in secrets from various sources
|
||||
using for example `$env` and `$file` keys.
|
||||
contain plain YAML, but with support for loading in data and secrets from
|
||||
various sources using for example `$env` and `$file` keys.
|
||||
|
||||
It is also possible to supply configuration through environment variables, for
|
||||
example `APP_CONFIG_app_baseUrl=https://staging.example.com`. However these
|
||||
|
||||
@@ -97,13 +97,13 @@ order:
|
||||
- If no config flags are provided, `app-config.local.yaml` has higher priority
|
||||
than `app-config.yaml`.
|
||||
|
||||
## Secrets and Dynamic Data
|
||||
## Includes and Dynamic Data
|
||||
|
||||
Secrets are supported via special data loading keys that are prefixed with `$`,
|
||||
which in turn provide a number of different ways to read in secrets. To load a
|
||||
configuration value as a secret, supply an object with one of the special secret
|
||||
keys, for example `$env` or `$file`. A full list of supported secret keys can be
|
||||
found below. For example, the following will read the config key
|
||||
Includes are supported via special data loading keys that are prefixed with `$`,
|
||||
which in turn provide a number of different ways to read in data. To load in an
|
||||
external configuration value, supply an object with one of the special include
|
||||
keys, for example `$env` or `$file`. A full list of supported include keys can
|
||||
be found below. For example, the following will read the config key
|
||||
`backend.mySecretKey` from the environment variable `MY_SECRET_KEY`:
|
||||
|
||||
```yaml
|
||||
@@ -114,43 +114,42 @@ backend:
|
||||
|
||||
With the above configuration, calling `config.getString('backend.mySecretKey')`
|
||||
will return the value of the environment variable `MY_SECRET_KEY` when the
|
||||
backend started up. All secrets are loaded at startup, so changing the contents
|
||||
of secret files or environment variables will not be reflected at runtime.
|
||||
backend started up. All includes are loaded at startup, so changing the contents
|
||||
of files or environment variables will not be reflected at runtime.
|
||||
|
||||
As hinted at, secrets can be loaded from a bunch of different sources, and can
|
||||
be extended with more. Below is a list of the currently supported methods for
|
||||
loading secrets.
|
||||
Below is a list of the currently supported methods for loading includes.
|
||||
|
||||
### Env Secrets
|
||||
### Env Includes
|
||||
|
||||
This reads a secret from an environment variable. For example, the following
|
||||
config loads the secret from the `MY_SECRET` env var.
|
||||
This reads a string value from an environment variable. For example, the
|
||||
following configuration loads the string value from the `MY_SECRET` environment
|
||||
variable.
|
||||
|
||||
```yaml
|
||||
$env: MY_SECRET
|
||||
```
|
||||
|
||||
### File Secrets
|
||||
### File Includes
|
||||
|
||||
This reads a secret from the entire contents of a file. The file path is
|
||||
relative to the `app-config.yaml` the defines the secrets. For example, the
|
||||
following reads the contents of `my-secret.txt` relative to the config file
|
||||
itself:
|
||||
This reads a string value from the entire contents of a text file. The file path
|
||||
is relative to the source config file. For example, the following reads the
|
||||
contents of `my-secret.txt` relative to the config file itself:
|
||||
|
||||
```yaml
|
||||
$file: ./my-secret.txt
|
||||
```
|
||||
|
||||
### Data File Secrets
|
||||
### Including Files
|
||||
|
||||
This reads secrets from a path within a JSON-like data file. The file path
|
||||
behaves similar to file secrets, but with the addition of a url fragment that is
|
||||
used to point to a specific value inside the file. Supported file extensions are
|
||||
`.json`, `.yaml`, and `.yml`. For example, the following would read out
|
||||
`my-secret-key` from `my-secrets.json`:
|
||||
The `$include` keyword can be used to load configuration values from an external
|
||||
file. It's able to load and parse data from `.json`, `.yml`, and `.yaml` files.
|
||||
It's also possible to include a url fragment (`#`) to point to a value at the
|
||||
given path in the file, using a dot-separated list of keys.
|
||||
|
||||
For example, the following would read `my-secret-key` from `my-secrets.json`:
|
||||
|
||||
```yaml
|
||||
$data: ./my-secrets.json#deployment.key
|
||||
$include: ./my-secrets.json#deployment.key
|
||||
```
|
||||
|
||||
Example `my-secrets.json` file:
|
||||
@@ -162,3 +161,19 @@ Example `my-secrets.json` file:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variable Substitution
|
||||
|
||||
Configuration files support environment variable substitution via a `${MY_VAR}`
|
||||
syntax. For example:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
baseUrl: https://${HOST}
|
||||
```
|
||||
|
||||
Note that all environment variables must be available, or the entire
|
||||
configuration value will evaluate to `undefined`.
|
||||
|
||||
The substitution syntax can be escaped using `$${...}`, which will be resolved
|
||||
as `${...}`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: figma
|
||||
title: Figma
|
||||
description: Documentation on using Figma to build your own plugins for
|
||||
Backstage
|
||||
# prettier-ignore
|
||||
description: Documentation on using Figma to build your own plugins for Backstage
|
||||
---
|
||||
|
||||
We have a [Figma component library](https://www.figma.com/@backstage) that you
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
id: overview
|
||||
title: Kubernetes
|
||||
sidebar_label: Overview
|
||||
description: Monitoring Kubernetes based services with the service catalog
|
||||
---
|
||||
|
||||
Kubernetes in Backstage is a way to monitor your service's current status when
|
||||
it is deployed on Kubernetes.
|
||||
|
||||
## Configuration
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
serviceLocatorMethod: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- 'config'
|
||||
clusters:
|
||||
- url: http://127.0.0.1:9999
|
||||
name: minikube
|
||||
authProvider: 'serviceAccount'
|
||||
serviceAccountToken:
|
||||
$env: K8S_MINIKUBE_TOKEN
|
||||
- url: http://127.0.0.2:9999
|
||||
name: gke-cluster-1
|
||||
authProvider: 'google'
|
||||
```
|
||||
|
||||
### serviceLocatorMethod
|
||||
|
||||
This configures how to determine which clusters a component is running in.
|
||||
|
||||
Currently, the only valid value is:
|
||||
|
||||
- `multiTenant` - This configuration assumes that all components run on all the
|
||||
provided clusters.
|
||||
|
||||
### clusterLocatorMethods
|
||||
|
||||
This is an array used to determine where to retrieve cluster configuration from.
|
||||
|
||||
Currently, the only valid cluster locator method is:
|
||||
|
||||
- `config` - This cluster locator method will read cluster information from your
|
||||
app-config (see below).
|
||||
|
||||
### clusters
|
||||
|
||||
Used by the `config` cluster locator method to construct Kubernetes clients.
|
||||
|
||||
### clusters.\*.url
|
||||
|
||||
The base URL to the Kubernetes control plane. Can be found by using the
|
||||
"Kubernetes master" result from running the `kubectl cluster-info` command.
|
||||
|
||||
### clusters.\*.name
|
||||
|
||||
A name to represent this cluster, this must be unique within the `clusters`
|
||||
array. Users will see this value in the Service Catalog Kubernetes plugin.
|
||||
|
||||
### clusters.\*.authProvider
|
||||
|
||||
This determines how the Kubernetes client authenticates with the Kubernetes
|
||||
cluster. Valid values are:
|
||||
|
||||
| Value | Description |
|
||||
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `serviceAccount` | This will use a Kubernetes [service account](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/) to access the Kubernetes API. When this is used the `serviceAccountToken` field should also be set. |
|
||||
| `google` | This will use a user's Google auth token from the [Google auth plugin](https://backstage.io/docs/auth/) to access the Kubernetes API. |
|
||||
|
||||
### clusters.\*.serviceAccount (optional)
|
||||
|
||||
The service account token to be used when using the `serviceAccount` auth
|
||||
provider.
|
||||
|
||||
## Role Based Access Control
|
||||
|
||||
The current RBAC permissions required are read-only cluster wide, for the
|
||||
following objects:
|
||||
|
||||
- pods
|
||||
- services
|
||||
- configmaps
|
||||
- deployments
|
||||
- replicasets
|
||||
- horizontalpodautoscalers
|
||||
- ingresses
|
||||
|
||||
## Surfacing your Kubernetes components as part of an entity
|
||||
|
||||
There are two ways to surface your Kubernetes components as part of an entity.
|
||||
The label selector takes precedence over the annotation/service id.
|
||||
|
||||
### Common `backstage.io/kubernetes-id` label
|
||||
|
||||
#### Adding the entity annotation
|
||||
|
||||
In order for Backstage to detect that an entity has Kubernetes components, the
|
||||
following annotation should be added to the entity's `catalog-info.yaml`:
|
||||
|
||||
```yaml
|
||||
annotations:
|
||||
'backstage.io/kubernetes-id': dice-roller
|
||||
```
|
||||
|
||||
#### Labeling Kubernetes components
|
||||
|
||||
In order for Kubernetes components to show up in the service catalog as a part
|
||||
of an entity, Kubernetes components themselves can have the following label:
|
||||
|
||||
```yaml
|
||||
'backstage.io/kubernetes-id': <BACKSTAGE_ENTITY_NAME>
|
||||
```
|
||||
|
||||
### Label selector query annotation
|
||||
|
||||
You can write your own custom label selector query that Backstage will use to
|
||||
lookup the objects (similar to `kubectl --selector="your query here"`). Review
|
||||
the
|
||||
[labels and selectors Kubernetes documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
|
||||
for more info.
|
||||
|
||||
```yaml
|
||||
'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end'
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
id: search-overview
|
||||
title: Search Documentation
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: Backstage Search lets you find the right information you are looking for in the Backstage ecosystem.
|
||||
---
|
||||
|
||||
# Backstage Search
|
||||
|
||||
## What is it?
|
||||
|
||||
Backstage Search lets you find the right information you are looking for in the
|
||||
Backstage ecosystem.
|
||||
|
||||
## Features
|
||||
|
||||
- A federated, faceted search, searching across all entities registered in your
|
||||
Backstage instance.
|
||||
|
||||
- A search that lets you plug in your own search engine of choice.
|
||||
|
||||
- A standardized search API where you can choose to index other plugins data.
|
||||
|
||||
## Project roadmap
|
||||
|
||||
| Version | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Backstage Search V.0 ✅ | Search Frontend letting you search through the entities of the software catalog. [See V.0 Use Cases.](#backstage-search-v0) |
|
||||
| Backstage Search V.1 ⌛ | Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog. [See V.1 Use Cases.](#backstage-search-v1) |
|
||||
| Backstage Search V.2 ⌛ | Search Backend responsible for the indexing process of entities, and their metadata, registered to the Software Catalog. [See V.2 Use Cases.](#backstage-search-v2) |
|
||||
| Backstage Search V.3 ⌛ | Standardized Search API lets you index other plugins data to the search engine of choice. [See V.3 Use Cases.](#backstage-search-v3) |
|
||||
|
||||
## Use Cases
|
||||
|
||||
#### Backstage Search V.0
|
||||
|
||||
- As a software engineer I should be able to navigate to a search page and
|
||||
search for entities registered in the Software Catalog.
|
||||
- As a software engineer I should be able to use the search input field in the
|
||||
sidebar to search for entities registered in the Software Catalog.
|
||||
- As a software engineer I should be able to see the number of results my search
|
||||
returned.
|
||||
- As a software engineer I should be able to filter on metadata (kind,
|
||||
lifecycle) when I’ve performed a search.
|
||||
- As a software engineer I should be able to hide the filters if I don’t need to
|
||||
use them.
|
||||
|
||||
#### Backstage Search V.1
|
||||
|
||||
- As a software engineer I should be able to get a match of a search on all
|
||||
entity metadata (e.g. owner, name, description, kind).
|
||||
- As an integrator I should not have to plug in any search engine, instead I can
|
||||
use the out of the box in-memory indexing process to index entities and their
|
||||
metadata registered in the Software Catalog.
|
||||
|
||||
#### Backstage Search V.2
|
||||
|
||||
- As an integrator I should be able to spin up an instance of ElasticSearch.
|
||||
- As an integrator I should be able to define a ElasticSearch cluster in my
|
||||
app_config.yaml where my data gets indexed to.
|
||||
|
||||
more to come...
|
||||
|
||||
#### Backstage Search V.3
|
||||
|
||||
- As a contributor I should be able to integrate plugin data to the indexing
|
||||
process of Backstage Search by using the standardized API.
|
||||
- As a software engineer I should be able to search for all content (for
|
||||
example, entities, metadata, documentation) in backstage search.
|
||||
|
||||
more to come...
|
||||
|
||||
## Search Engines Supported
|
||||
|
||||
See [Backstage Search Architecture](architecture.md) to get an overview of how
|
||||
the search engines are used.
|
||||
|
||||
| Search Engine | Support Status |
|
||||
| ------------- | -------------- |
|
||||
| ElasticSearch | Not yet ❌ |
|
||||
|
||||
[Reach out to us](#feedback) if you want to chat about support for more search
|
||||
engines.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Stack | Location |
|
||||
| --------------- | ------------------------ |
|
||||
| Frontend Plugin | @backstage/plugin-search |
|
||||
| Backend Plugin | ⌛ |
|
||||
|
||||
## Feedback
|
||||
|
||||
For any questions of feedback, reach out to us in the `#search` channel of our
|
||||
[Discord chatroom](https://github.com/backstage/backstage#community).
|
||||
|
||||
We are still looking for feedback to improve the architecture to fit your
|
||||
use-case, see
|
||||
[this open issue](https://github.com/backstage/backstage/issues/4078).
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
id: architecture
|
||||
title: Search Architecture
|
||||
description: Documentation on Search Architecture
|
||||
---
|
||||
|
||||
# Search Architecture
|
||||
|
||||
> _This is a proposed architecture which has not been implemented yet. We are
|
||||
> still looking for feedback to improve the architecture to fit your use-case,
|
||||
> see [this open issue](https://github.com/backstage/backstage/issues/4078)._
|
||||
|
||||
Below you can explore the Search Architecture. Our aim with this architecture is
|
||||
to support a wide variety of search engines, while providing a simple developer
|
||||
experience for plugin developers, and a good out-of-the-box experience for
|
||||
Backstage end-users.
|
||||
|
||||
<img data-zoomable src="../../assets/search/architecture.drawio.svg" alt="Search Architecture" />
|
||||
|
||||
At a base-level, we want to support the following:
|
||||
|
||||
- We aim to enable the capability to search across the entire Backstage
|
||||
ecosystem by decoupling search from content management.
|
||||
- We aim to enable the capability to deploy Backstage using any search engine,
|
||||
by providing an integration and translation layer between the core search
|
||||
plugin and search engine specific logic that can be extended for different
|
||||
search engines. We may also introduce the ability to replace the backend API
|
||||
endpoint with a custom endpoint for simpler customization.
|
||||
|
||||
More advanced use-cases we hope to support with this architecture include:
|
||||
|
||||
- It should be easy for any plugin to expose new content to search. (e.g. entity
|
||||
metadata, documentation from TechDocs)
|
||||
- It should be easy for any plugin to append relevant metadata to existing
|
||||
content in search. (e.g. location (path) for TechDocs page)
|
||||
- It should be easy to refine search queries (e.g. ranking, scoring, etc.)
|
||||
- It should be easy to customize the search UI
|
||||
- It should be easy to add search functionality to any Backstage plugin or
|
||||
deployment
|
||||
@@ -60,7 +60,7 @@ data from. Each entry is a structure with up to four elements:
|
||||
and raw. If it is not supplied, anonymous access will be used.
|
||||
- `apiBaseUrl` (optional): If you want to communicate using the APIv3 method
|
||||
with this provider, specify the base URL for its endpoint here, with no
|
||||
trailing slash. Specifically when the target is github, you can leave it out
|
||||
trailing slash. Specifically when the target is GitHub, you can leave it out
|
||||
to be inferred automatically. For a GitHub Enterprise installation, it is
|
||||
commonly at `https://api.<host>` or `https://<host>/api/v3`.
|
||||
- `rawBaseUrl` (optional): If you want to communicate using the raw HTTP method
|
||||
|
||||
@@ -60,7 +60,7 @@ software catalog API.
|
||||
},
|
||||
"spec": {
|
||||
"lifecycle": "production",
|
||||
"owner": "artist-relations@example.com",
|
||||
"owner": "artist-relations-team",
|
||||
"type": "website"
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ metadata:
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: artist-relations@example.com
|
||||
owner: artist-relations-team
|
||||
```
|
||||
|
||||
The root fields `apiVersion`, `kind`, `metadata`, and `spec` are part of the
|
||||
@@ -131,6 +131,19 @@ spec:
|
||||
$text: https://petstore.swagger.io/v2/swagger.json
|
||||
```
|
||||
|
||||
Note that to be able to read from targets that are outside of the normal
|
||||
integration points such as `github.com`, you'll need to explicitly allow it by
|
||||
adding an entry in the `backend.reading.allow` list. For example:
|
||||
|
||||
```yml
|
||||
backend:
|
||||
baseUrl: ...
|
||||
reading:
|
||||
allow:
|
||||
- host: example.com
|
||||
- host: '*.examples.org'
|
||||
```
|
||||
|
||||
## Common to All Kinds: The Envelope
|
||||
|
||||
The root envelope object has the following structure.
|
||||
@@ -268,7 +281,7 @@ identical in use to
|
||||
|
||||
Their purpose is mainly, but not limited, to reference into external systems.
|
||||
This could for example be a reference to the git ref the entity was ingested
|
||||
from, to monitoring and logging systems, to pagerduty schedules, etc. Users may
|
||||
from, to monitoring and logging systems, to PagerDuty schedules, etc. Users may
|
||||
add these to descriptor YAML files, but in addition to this automated systems
|
||||
may also add annotations, either during ingestion into the catalog, or at a
|
||||
later time.
|
||||
@@ -381,7 +394,8 @@ metadata:
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: artist-relations@example.com
|
||||
owner: artist-relations-team
|
||||
system: artist-engagement-portal
|
||||
providesApis:
|
||||
- artist-api
|
||||
```
|
||||
@@ -427,8 +441,8 @@ The current set of well-known and common values for this field is:
|
||||
|
||||
### `spec.owner` [required]
|
||||
|
||||
The owner of the component, e.g. `artist-relations@example.com`. This field is
|
||||
required.
|
||||
An [entity reference](#string-references) to the owner of the component, e.g.
|
||||
`artist-relations-team`. This field is required.
|
||||
|
||||
In Backstage, the owner of a component is the singular entity (commonly a team)
|
||||
that bears ultimate responsibility for the component, and has the authority and
|
||||
@@ -440,25 +454,45 @@ not to be used by automated processes to for example assign authorization in
|
||||
runtime systems. There may be others that also develop or otherwise touch the
|
||||
component, but there will always be one ultimate owner.
|
||||
|
||||
Apart from being a string, the software catalog leaves the format of this field
|
||||
open to implementers to choose. Most commonly, it is set to the ID or email of a
|
||||
group of people in an organizational structure.
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
|
||||
|
||||
### `spec.system` [optional]
|
||||
|
||||
An [entity reference](#string-references) to the system that the component
|
||||
belongs to, e.g. `artist-engagement-portal`. This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| [`System`](#kind-system) (default) | Same as this entity, typically `default` | [`partOf`, and reverse `hasPart`](well-known-relations.md#partof-and-haspart) |
|
||||
|
||||
### `spec.subcomponentOf` [optional]
|
||||
|
||||
An [entity reference](#string-references) to another component of which the
|
||||
component is a part, e.g. `spotify-ios-app`. This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ---------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| [`Component`](#kind-component) (default) | Same as this entity, typically `default` | [`partOf`, and reverse `hasPart`](well-known-relations.md#partof-and-haspart) |
|
||||
|
||||
### `spec.providesApis` [optional]
|
||||
|
||||
Links APIs that are provided by the component, e.g. `artist-api`. This field is
|
||||
optional.
|
||||
An array of [entity references](#string-references) to the APIs that are
|
||||
provided by the component, e.g. `artist-api`. This field is optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------- |
|
||||
| [`API`](#kind-api) (default) | Same as this entity, typically `default` | [`providesApi`, and reverse `apiProvidedBy`](well-known-relations.md#providesapi-and-apiprovidedby) |
|
||||
|
||||
### `spec.consumesApis` [optional]
|
||||
|
||||
Links APIs that are consumed by the component, e.g. `artist-api`. This field is
|
||||
optional.
|
||||
An array of [entity references](#string-references) to the APIs that are
|
||||
consumed by the component, e.g. `artist-api`. This field is optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------- |
|
||||
| [`API`](#kind-api) (default) | Same as this entity, typically `default` | [`consumesApi`, and reverse `apiConsumedBy`](well-known-relations.md#consumesapi-and-apiconsumedby) |
|
||||
|
||||
## Kind: Template
|
||||
|
||||
@@ -597,7 +631,8 @@ metadata:
|
||||
spec:
|
||||
type: openapi
|
||||
lifecycle: production
|
||||
owner: artist-relations@example.com
|
||||
owner: artist-relations-team
|
||||
system: artist-engagement-portal
|
||||
definition: |
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
@@ -663,8 +698,8 @@ The current set of well-known and common values for this field is:
|
||||
|
||||
### `spec.owner` [required]
|
||||
|
||||
The owner of the API, e.g. `artist-relations@example.com`. This field is
|
||||
required.
|
||||
An [entity reference](#string-references) to the owner of the component, e.g.
|
||||
`artist-relations-team`. This field is required.
|
||||
|
||||
In Backstage, the owner of an API is the singular entity (commonly a team) that
|
||||
bears ultimate responsibility for the API, and has the authority and capability
|
||||
@@ -676,9 +711,18 @@ processes to for example assign authorization in runtime systems. There may be
|
||||
others that also develop or otherwise touch the API, but there will always be
|
||||
one ultimate owner.
|
||||
|
||||
Apart from being a string, the software catalog leaves the format of this field
|
||||
open to implementers to choose. Most commonly, it is set to the ID or email of a
|
||||
group of people in an organizational structure.
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
|
||||
|
||||
### `spec.system` [optional]
|
||||
|
||||
An [entity reference](#string-references) to the system that the API belongs to,
|
||||
e.g. `artist-engagement-portal`. This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| [`System`](#kind-system) (default) | Same as this entity, typically `default` | [`partOf`, and reverse `hasPart`](well-known-relations.md#partof-and-haspart) |
|
||||
|
||||
### `spec.definition` [required]
|
||||
|
||||
@@ -751,11 +795,11 @@ parent; the catalog supports multi-root hierarchies. Groups may however not have
|
||||
more than one parent.
|
||||
|
||||
This field is an
|
||||
[entity reference](https://backstage.io/docs/features/software-catalog/references),
|
||||
with the default kind `Group` and the default namespace equal to the same
|
||||
namespace as the user. Only `Group` entities may be referenced. Most commonly,
|
||||
this field points to a group in the same namespace, so in those cases it is
|
||||
sufficient to enter only the `metadata.name` field of that group.
|
||||
[entity reference](https://backstage.io/docs/features/software-catalog/references).
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default) | Same as this entity, typically `default` | [`childOf`, and reverse `parentOf`](well-known-relations.md#parentof-and-childof) |
|
||||
|
||||
### `spec.children` [required]
|
||||
|
||||
@@ -765,11 +809,11 @@ no child groups. The items are not guaranteed to be ordered in any particular
|
||||
way.
|
||||
|
||||
The entries of this array are
|
||||
[entity references](https://backstage.io/docs/features/software-catalog/references),
|
||||
with the default kind `Group` and the default namespace equal to the same
|
||||
namespace as the user. Only `Group` entities may be referenced. Most commonly,
|
||||
these entries point to groups in the same namespace, so in those cases it is
|
||||
sufficient to enter only the `metadata.name` field of those groups.
|
||||
[entity references](https://backstage.io/docs/features/software-catalog/references).
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default) | Same as this entity, typically `default` | [`hasMember`, and reverse `memberOf`](well-known-relations.md#memberof-and-hasmember) |
|
||||
|
||||
## Kind: User
|
||||
|
||||
@@ -825,23 +869,200 @@ user is not member of any groups. The items are not guaranteed to be ordered in
|
||||
any particular way.
|
||||
|
||||
The entries of this array are
|
||||
[entity references](https://backstage.io/docs/features/software-catalog/references),
|
||||
with the default kind `Group` and the default namespace equal to the same
|
||||
namespace as the user. Only `Group` entities may be referenced. Most commonly,
|
||||
these entries point to groups in the same namespace, so in those cases it is
|
||||
sufficient to enter only the `metadata.name` field of those groups.
|
||||
[entity references](https://backstage.io/docs/features/software-catalog/references).
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default) | Same as this entity, typically `default` | [`memberOf`, and reverse `hasMember`](well-known-relations.md#memberof-and-hasmember) |
|
||||
|
||||
## Kind: Resource
|
||||
|
||||
This kind is not yet defined, but is reserved [for future use](system-model.md).
|
||||
Describes the following entity kind:
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ----------------------- |
|
||||
| `apiVersion` | `backstage.io/v1alpha1` |
|
||||
| `kind` | `Resource` |
|
||||
|
||||
A resource describes the infrastructure a system needs to operate, like BigTable
|
||||
databases, Pub/Sub topics, S3 buckets or CDNs. Modelling them together with
|
||||
components and systems allows to visualize resource footprint, and create
|
||||
tooling around them.
|
||||
|
||||
Descriptor files for this kind may look as follows.
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Resource
|
||||
metadata:
|
||||
name: artists-db
|
||||
description: Stores artist details
|
||||
spec:
|
||||
type: database
|
||||
owner: artist-relations-team
|
||||
system: artist-engagement-portal
|
||||
```
|
||||
|
||||
In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata)
|
||||
shape, this kind has the following structure.
|
||||
|
||||
### `apiVersion` and `kind` [required]
|
||||
|
||||
Exactly equal to `backstage.io/v1alpha1` and `Resource`, respectively.
|
||||
|
||||
### `spec.owner` [required]
|
||||
|
||||
An [entity reference](#string-references) to the owner of the resource, e.g.
|
||||
`artist-relations-team`. This field is required.
|
||||
|
||||
In Backstage, the owner of a resource is the singular entity (commonly a team)
|
||||
that bears ultimate responsibility for the resource, and has the authority and
|
||||
capability to develop and maintain it. They will be the point of contact if
|
||||
something goes wrong, or if features are to be requested. The main purpose of
|
||||
this field is for display purposes in Backstage, so that people looking at
|
||||
catalog items can get an understanding of to whom this resource belongs. It is
|
||||
not to be used by automated processes to for example assign authorization in
|
||||
runtime systems. There may be others that also manage or otherwise touch the
|
||||
resource, but there will always be one ultimate owner.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
|
||||
|
||||
### `spec.type` [required]
|
||||
|
||||
The type of resource as a string, e.g. `database`. This field is required. There
|
||||
is currently no enforced set of values for this field, so it is left up to the
|
||||
adopting organization to choose a nomenclature that matches the resources used
|
||||
in their tech stack.
|
||||
|
||||
Some common values for this field could be:
|
||||
|
||||
- `database`
|
||||
- `s3-bucket`
|
||||
- `cluster`
|
||||
|
||||
### `spec.system` [optional]
|
||||
|
||||
An [entity reference](#string-references) to the system that the resource
|
||||
belongs to, e.g. `artist-engagement-portal`. This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| [`System`](#kind-system) (default) | Same as this entity, typically `default` | [`partOf`, and reverse `hasPart`](well-known-relations.md#partof-and-haspart) |
|
||||
|
||||
## Kind: System
|
||||
|
||||
This kind is not yet defined, but is reserved [for future use](system-model.md).
|
||||
Describes the following entity kind:
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ----------------------- |
|
||||
| `apiVersion` | `backstage.io/v1alpha1` |
|
||||
| `kind` | `System` |
|
||||
|
||||
A system is a collection of resources and components. The system may expose or
|
||||
consume one or several APIs. It is viewed as abstraction level that provides
|
||||
potential consumers insights into exposed features without needing a too
|
||||
detailed view into the details of all components. This also gives the owning
|
||||
team the possibility to decide about published artifacts and APIs.
|
||||
|
||||
Descriptor files for this kind may look as follows.
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: System
|
||||
metadata:
|
||||
name: artist-engagement-portal
|
||||
description: Handy tools to keep artists in the loop
|
||||
spec:
|
||||
owner: artist-relations-team
|
||||
domain: artists
|
||||
```
|
||||
|
||||
In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata)
|
||||
shape, this kind has the following structure.
|
||||
|
||||
### `apiVersion` and `kind` [required]
|
||||
|
||||
Exactly equal to `backstage.io/v1alpha1` and `System`, respectively.
|
||||
|
||||
### `spec.owner` [required]
|
||||
|
||||
An [entity reference](#string-references) to the owner of the system, e.g.
|
||||
`artist-relations-team`. This field is required.
|
||||
|
||||
In Backstage, the owner of a system is the singular entity (commonly a team)
|
||||
that bears ultimate responsibility for the system, and has the authority and
|
||||
capability to develop and maintain it. They will be the point of contact if
|
||||
something goes wrong, or if features are to be requested. The main purpose of
|
||||
this field is for display purposes in Backstage, so that people looking at
|
||||
catalog items can get an understanding of to whom this system belongs. It is not
|
||||
to be used by automated processes to for example assign authorization in runtime
|
||||
systems. There may be others that also develop or otherwise touch the system,
|
||||
but there will always be one ultimate owner.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
|
||||
|
||||
### `spec.domain` [optional]
|
||||
|
||||
An [entity reference](#string-references) to the domain that the system belongs
|
||||
to, e.g. `artists`. This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| [`Domain`](#kind-domain) (default) | Same as this entity, typically `default` | [`partOf`, and reverse `hasPart`](well-known-relations.md#partof-and-haspart) |
|
||||
|
||||
## Kind: Domain
|
||||
|
||||
This kind is not yet defined, but is reserved [for future use](system-model.md).
|
||||
Describes the following entity kind:
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ----------------------- |
|
||||
| `apiVersion` | `backstage.io/v1alpha1` |
|
||||
| `kind` | `Domain` |
|
||||
|
||||
A Domain groups a collection of systems that share terminology, domain models,
|
||||
business purpose, or documentation, i.e. form a bounded context.
|
||||
|
||||
Descriptor files for this kind may look as follows.
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Domain
|
||||
metadata:
|
||||
name: artists
|
||||
description: Everything about artists
|
||||
spec:
|
||||
owner: artist-relations-team
|
||||
```
|
||||
|
||||
In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata)
|
||||
shape, this kind has the following structure.
|
||||
|
||||
### `apiVersion` and `kind` [required]
|
||||
|
||||
Exactly equal to `backstage.io/v1alpha1` and `Domain`, respectively.
|
||||
|
||||
### `spec.owner` [required]
|
||||
|
||||
An [entity reference](#string-references) to the owner of the domain, e.g.
|
||||
`artist-relations-team`. This field is required.
|
||||
|
||||
In Backstage, the owner of a domain is the singular entity (commonly a team)
|
||||
that bears ultimate responsibility for the domain, and has the authority and
|
||||
capability to develop and maintain it. They will be the point of contact if
|
||||
something goes wrong, or if features are to be requested. The main purpose of
|
||||
this field is for display purposes in Backstage, so that people looking at
|
||||
catalog items can get an understanding of to whom this domain belongs. It is not
|
||||
to be used by automated processes to for example assign authorization in runtime
|
||||
systems. There may be others that also develop or otherwise touch the domain,
|
||||
but there will always be one ultimate owner.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
|
||||
|
||||
## Kind: Location
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ The recommended way of instantiating the catalog backend classes is to use the
|
||||
as illustrated in the
|
||||
[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/catalog.ts).
|
||||
We will create a new
|
||||
[`CatalogProcessor`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/ingestion/types.ts)
|
||||
[`CatalogProcessor`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/ingestion/processors/types.ts)
|
||||
subclass that can be added to this catalog builder.
|
||||
|
||||
It is up to you where you put the code for this new processor class. For quick
|
||||
|
||||
@@ -23,7 +23,7 @@ We model software in the Backstage catalogue using these three core entities
|
||||
- **Resources** are physical or virtual infrastructure needed to operate a
|
||||
component
|
||||
|
||||

|
||||

|
||||
|
||||
### Component
|
||||
|
||||
@@ -44,8 +44,8 @@ Backstage model and the primary way to discover existing functionality in the
|
||||
ecosystem.
|
||||
|
||||
APIs are implemented by components and form boundaries between components. They
|
||||
might be defined using an RPC IDL (eg Protobuf, GraphQL, ...), a data schema (eg
|
||||
Avro, TFRecord, ...), or as code interfaces. In any case, APIs exposed by
|
||||
might be defined using an RPC IDL (e.g., Protobuf, GraphQL, ...), a data schema
|
||||
(e.g., Avro, TFRecord, ...), or as code interfaces. In any case, APIs exposed by
|
||||
components need to be in a known machine-readable format so we can build further
|
||||
tooling and analysis on top.
|
||||
|
||||
@@ -73,6 +73,8 @@ these entities using the following (optional) concepts:
|
||||
function
|
||||
- **Domains** relate entities and systems to part of the business
|
||||
|
||||

|
||||
|
||||
### System
|
||||
|
||||
With increasing complexity in software, systems form an important abstraction
|
||||
@@ -107,10 +109,6 @@ product or use-case, share the same entity types in their APIs, and integrate
|
||||
well with each other. Other domains could be “Content Ingestion”, “Ads” or
|
||||
“Search”.
|
||||
|
||||
## Current status
|
||||
|
||||
Backstage currently supports Components and APIs.
|
||||
|
||||
## Links
|
||||
|
||||
- [Original RFC](https://github.com/backstage/backstage/issues/390)
|
||||
|
||||
@@ -22,7 +22,7 @@ use.
|
||||
# Example:
|
||||
metadata:
|
||||
annotations:
|
||||
backstage.io/managed-by-location: github:http://github.com/backstage/backstage/catalog-info.yaml
|
||||
backstage.io/managed-by-location: url:http://github.com/backstage/backstage/blob/master/catalog-info.yaml
|
||||
```
|
||||
|
||||
The value of this annotation is a so called location reference string, that
|
||||
@@ -30,8 +30,8 @@ points to the source from which the entity was originally fetched. This
|
||||
annotation is added automatically by the catalog as it fetches the data from a
|
||||
registered location, and is not meant to normally be written by humans. The
|
||||
annotation may point to any type of generic location that the catalog supports,
|
||||
so it cannot be relied on to always be specifically of type `github`, nor that
|
||||
it even represents a single file. Note also that a single location can be the
|
||||
so it cannot be relied on to always be specifically of type `url`, nor that it
|
||||
even represents a single file. Note also that a single location can be the
|
||||
source of many entities, so it represents a many-to-one relationship.
|
||||
|
||||
The format of the value is `<type>:<target>`. Note that the target may also
|
||||
@@ -40,13 +40,30 @@ expecting a two-item array out of it. The format of the target part is
|
||||
type-dependent and could conceivably even be an empty string, but the separator
|
||||
colon is always present.
|
||||
|
||||
### backstage.io/managed-by-origin-location
|
||||
|
||||
```yaml
|
||||
# Example:
|
||||
metadata:
|
||||
annotations:
|
||||
backstage.io/managed-by-origin-location: url:http://github.com/backstage/backstage/blob/master/catalog-info.yaml
|
||||
```
|
||||
|
||||
The value of this annotation is a location reference string (see above). It
|
||||
points to the location, whose registration lead to the creation of the entity.
|
||||
In most cases, the `backstage.io/managed-by-location` and
|
||||
`backstage.io/managed-by-origin-location` will be equal. They will be different
|
||||
if the original location delegates to another location. A common case is, that a
|
||||
location is registered as `bootstrap:bootstrap` which means that it is part of
|
||||
the `app-config.yaml` of a Backstage installation.
|
||||
|
||||
### backstage.io/techdocs-ref
|
||||
|
||||
```yaml
|
||||
# Example:
|
||||
metadata:
|
||||
annotations:
|
||||
backstage.io/techdocs-ref: github:https://github.com/backstage/backstage.git
|
||||
backstage.io/techdocs-ref: url:https://github.com/backstage/backstage/tree/master
|
||||
```
|
||||
|
||||
The value of this annotation is a location reference string (see above). If this
|
||||
|
||||
@@ -48,11 +48,10 @@ where present.
|
||||
### `providesApi` and `apiProvidedBy`
|
||||
|
||||
A relation with an [API](descriptor-format.md#kind-api) entity, typically from a
|
||||
[Component](descriptor-format.md#kind-component) or
|
||||
[System](descriptor-format.md#kind-system).
|
||||
[Component](descriptor-format.md#kind-component).
|
||||
|
||||
These relations express that a component or system exposes an API - meaning that
|
||||
it hosts callable endpoints from which you can consume that API.
|
||||
These relations express that a component exposes an API - meaning that it hosts
|
||||
callable endpoints from which you can consume that API.
|
||||
|
||||
This relation is commonly generated based on `spec.providesApis` of the
|
||||
component or system in question.
|
||||
@@ -60,11 +59,10 @@ component or system in question.
|
||||
### `consumesApi` and `apiConsumedBy`
|
||||
|
||||
A relation with an [API](descriptor-format.md#kind-api) entity, typically from a
|
||||
[Component](descriptor-format.md#kind-component) or
|
||||
[System](descriptor-format.md#kind-system).
|
||||
[Component](descriptor-format.md#kind-component).
|
||||
|
||||
These relations express that a component or system consumes an API - meaning
|
||||
that it depends on endpoints of the API.
|
||||
These relations express that a component consumes an API - meaning that it
|
||||
depends on endpoints of the API.
|
||||
|
||||
This relation is commonly generated based on `spec.consumesApis` of the
|
||||
component or system in question.
|
||||
@@ -91,3 +89,18 @@ A membership relation, typically for [Users](descriptor-format.md#kind-user) in
|
||||
[Groups](descriptor-format.md#kind-group).
|
||||
|
||||
This relation is commonly based on `spec.memberOf`.
|
||||
|
||||
### `partOf` and `hasPart`
|
||||
|
||||
A relation with a [Domain](descriptor-format.md#kind-domain),
|
||||
[System](descriptor-format.md#kind-system) or
|
||||
[Component](descriptor-format.md#kind-component) entity, typically from a
|
||||
[Component](descriptor-format.md#kind-component),
|
||||
[API](descriptor-format.md#kind-api), or
|
||||
[System](descriptor-format.md#kind-system).
|
||||
|
||||
These relations express that a component belongs to a larger component; a
|
||||
component, API or resource belongs to a system; or that a system is grouped
|
||||
under a domain.
|
||||
|
||||
This relation is commonly based on `spec.system` or `spec.domain`.
|
||||
|
||||
@@ -57,7 +57,7 @@ That type looks like the following:
|
||||
export type PublisherBase = {
|
||||
publish(opts: {
|
||||
entity: TemplateEntityV1alpha1;
|
||||
values: RequiredTemplateValues & Record<string, JsonValue>;
|
||||
values: TemplaterValues;
|
||||
directory: string;
|
||||
}): Promise<{ remoteUrl: string }>;
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ That type looks like the following:
|
||||
```ts
|
||||
export type TemplaterRunOptions = {
|
||||
directory: string;
|
||||
values: RequiredTemplateValues & Record<string, JsonValue>;
|
||||
values: TemplaterValues;
|
||||
logStream?: Writable;
|
||||
dockerClient: Docker;
|
||||
};
|
||||
@@ -86,10 +86,11 @@ follows:
|
||||
|
||||
_note_ Currently the templaters that we provide are basically Docker action
|
||||
containers that are run on top of the skeleton folder. This keeps dependencies
|
||||
to a minimal for running backstage scaffolder, but you don't /have/ to use
|
||||
Docker. You could create your own templater that spins up an EC2 instance and
|
||||
downloads the folder and does everything using an AMI if you want. It's entirely
|
||||
up to you!
|
||||
to a minimum for running backstage scaffolder, but you don't _have_ to use
|
||||
Docker. You can `pip install cookiecutter` to run it locally in your backend.
|
||||
You could create your own templater that spins up an EC2 instance and downloads
|
||||
the folder and does everything using an AMI if you want. It's entirely up to
|
||||
you!
|
||||
|
||||
Now it's up to you to implement the `run` function, and then return a
|
||||
`TemplaterRunResult` which is `{ resultDir: string }`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
id: software-templates-index
|
||||
title: Backstage Software Templates
|
||||
sidebar_label: Overview
|
||||
description: The Software Templates part of Backstage is a tool that can help
|
||||
you create Components inside Backstage
|
||||
# prettier-ignore
|
||||
description: The Software Templates part of Backstage is a tool that can help you create Components inside Backstage
|
||||
---
|
||||
|
||||
The Software Templates part of Backstage is a tool that can help you create
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
id: techdocs-overview
|
||||
title: TechDocs Documentation
|
||||
sidebar_label: Overview
|
||||
description: TechDocs is Spotify’s homegrown docs-like-code solution built
|
||||
directly into Backstage
|
||||
# prettier-ignore
|
||||
description: TechDocs is Spotify’s homegrown docs-like-code solution built directly into Backstage
|
||||
---
|
||||
|
||||
## What is it?
|
||||
@@ -45,8 +45,6 @@ about TechDocs and the philosophy in its
|
||||
[v2]: https://github.com/backstage/backstage/milestone/22
|
||||
[v3]: https://github.com/backstage/backstage/milestone/17
|
||||
|
||||
<!-- TODO: Add link to milestone for v3 -->
|
||||
|
||||
## Use Cases
|
||||
|
||||
#### TechDocs V.0
|
||||
@@ -110,12 +108,12 @@ providers are used.
|
||||
| GitLab | Yes ✅ |
|
||||
| GitLab Enterprise | Yes ✅ |
|
||||
|
||||
| File Storage Provider | Support Status | Track status |
|
||||
| --------------------------------- | -------------- | ----------------------------------------------------------- |
|
||||
| Local Filesystem of Backstage app | Yes ✅ | |
|
||||
| Google Cloud Storage (GCS) | Yes ✅ | |
|
||||
| Amazon Web Services (AWS) S3 | No ❌ | [#3714](https://github.com/backstage/backstage/issues/3714) |
|
||||
| Azure Storage | No ❌ | |
|
||||
| File Storage Provider | Support Status |
|
||||
| --------------------------------- | ----------------------------------------------------------------- |
|
||||
| Local Filesystem of Backstage app | Yes ✅ |
|
||||
| Google Cloud Storage (GCS) | Yes ✅ |
|
||||
| Amazon Web Services (AWS) S3 | Yes ✅ |
|
||||
| Azure Storage | No ❌ [#3938](https://github.com/backstage/backstage/issues/3938) |
|
||||
|
||||
[Reach out to us](#feedback) if you want to request more platforms.
|
||||
|
||||
|
||||
@@ -123,6 +123,20 @@ a cache for the generated static content. TechDocs is also currently built on
|
||||
MkDocs which does not allow us to generate docs per-page, so we would have to
|
||||
build all docs for a entity on every request.
|
||||
|
||||
**Q. Can you use the techdocs plugin without the techdocs-backend plugin?**
|
||||
|
||||
A: `techdocs` and `techdocs-backend` plugins are designed to be used together,
|
||||
like any other Backstage plugin with a frontend and its backend (catalog,
|
||||
scaffolder, etc.). If you set your Backstage instance to generate docs on the
|
||||
server, `techdocs-backend` will be responsible for managing the whole build
|
||||
process, making sure it's scalable. It is responsible for securely communicating
|
||||
with the cloud storage provider, for both fetching static generated sites and
|
||||
publishing the updates. There are other planned features like an authentication
|
||||
layer for users to determine whether they have the permission to view a
|
||||
particular docs site. There are a handful of features which are extremely hard
|
||||
to develop without a tightly integrated backend in place. Hence, support for
|
||||
`techdocs` without `techdocs-backend` is limited and challenging to develop.
|
||||
|
||||
# Future work
|
||||
|
||||
_Ideas here are far fetched and not in the project's milestone for near future
|
||||
@@ -142,12 +156,11 @@ Status of all the features mentioned above.
|
||||
|
||||
- Basic setup with techdocs-backend file server as storage.
|
||||
- Basic setup with cloud storage solution.
|
||||
|
||||
**Work in progress 🚧**
|
||||
|
||||
- `techdocs-cli` is able to generate docs in CI/CD environment.
|
||||
- `techdocs-cli` is able to publish docs site to any storage.
|
||||
|
||||
**Work in progress 🚧**
|
||||
|
||||
**Not implemented yet ❌**
|
||||
|
||||
- `techdocs-backend` integration with Backstage access control management.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: concepts
|
||||
title: Concepts
|
||||
description: Documentation on concepts that are introduced with
|
||||
Spotify's docs-like-code solution in Backstage
|
||||
# prettier-ignore
|
||||
description: Documentation on concepts that are introduced with Spotify's docs-like-code solution in Backstage
|
||||
---
|
||||
|
||||
This page describes concepts that are introduced with Spotify's docs-like-code
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: configuration
|
||||
title: TechDocs Configuration Options
|
||||
description:
|
||||
Reference documentation for configuring TechDocs using app-config.yaml
|
||||
# prettier-ignore
|
||||
description: Reference documentation for configuring TechDocs using app-config.yaml
|
||||
---
|
||||
|
||||
Using the `app-config.yaml` in the Backstage app, you can configure TechDocs
|
||||
@@ -13,18 +13,15 @@ configuration options for TechDocs.
|
||||
# File: app-config.yaml
|
||||
|
||||
techdocs:
|
||||
|
||||
# TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
|
||||
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
|
||||
|
||||
# Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
|
||||
# to serve files from either a local directory or an External storage provider.
|
||||
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
|
||||
|
||||
# generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to
|
||||
# spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of).
|
||||
# You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running
|
||||
@@ -34,7 +31,6 @@ techdocs:
|
||||
generators:
|
||||
techdocs: 'docker'
|
||||
|
||||
|
||||
# techdocs.builder can be either 'local' or 'external.
|
||||
# If builder is set to 'local' and you open a TechDocs page, techdocs-backend will try to generate the docs, publish to storage
|
||||
# and show the generated docs afterwords. This is the "Basic" setup of the TechDocs Architecture.
|
||||
@@ -44,30 +40,48 @@ techdocs:
|
||||
|
||||
builder: 'local'
|
||||
|
||||
|
||||
# techdocs.publisher is used to configure the Storage option, whether you want to use the local filesystem to store generated docs
|
||||
# or you want to use External storage providers like Google Cloud Storage, AWS S3, etc.
|
||||
|
||||
publisher:
|
||||
|
||||
# techdocs.publisher.type can be - 'local' or 'googleGcs' (awsS3, azureStorage, etc. to be available as well).
|
||||
# techdocs.publisher.type can be - 'local' or 'googleGcs' or 'awsS3' (azureStorage to be available in future).
|
||||
# When set to 'local', techdocs-backend will create a 'static' directory at its root to store generated documentation files.
|
||||
# When set to 'googleGcs', techdocs-backend will use a Google Cloud Storage Bucket to store generated documentation files.
|
||||
# When set to 'awsS3', techdocs-backend will use an Amazon Web Service (AWS) S3 bucket to store generated documentation files.
|
||||
|
||||
type: 'local'
|
||||
|
||||
|
||||
# Required when techdocs.publisher.type is set to 'googleGcs'. Skip otherwise.
|
||||
|
||||
googleGcs:
|
||||
# An API key is required to write to a storage bucket.
|
||||
# (Required) Cloud Storage Bucket Name
|
||||
bucketName: 'techdocs-storage'
|
||||
|
||||
# (Optional) An API key is required to write to a storage bucket.
|
||||
# If missing, GOOGLE_APPLICATION_CREDENTIALS environment variable will be used.
|
||||
# https://cloud.google.com/docs/authentication/production
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json',
|
||||
$file: '/path/to/google_application_credentials.json'
|
||||
|
||||
# Your GCP Project ID where the Cloud Storage Bucket is hosted.
|
||||
projectId: 'gcp-project-id'
|
||||
# Required when techdocs.publisher.type is set to 'awsS3'. Skip otherwise.
|
||||
|
||||
# Cloud Storage Bucket Name
|
||||
bucketName: 'techdocs-storage',
|
||||
awsS3:
|
||||
# (Required) AWS S3 Bucket Name
|
||||
bucketName: 'techdocs-storage'
|
||||
|
||||
# (Optional) An API key is required to write to a storage bucket.
|
||||
# If not set, environment variables or aws config file will be used to authenticate.
|
||||
# https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html
|
||||
# https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-shared.html
|
||||
credentials:
|
||||
accessKeyId:
|
||||
$env: TECHDOCS_AWSS3_ACCESS_KEY_ID_CREDENTIAL
|
||||
secretAccessKey:
|
||||
$env: TECHDOCS_AWSS3_SECRET_ACCESS_KEY_CREDENTIAL
|
||||
|
||||
# (Optional) AWS Region of the bucket.
|
||||
# If not set, AWS_REGION environment variable or aws config file will be used.
|
||||
# https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html
|
||||
region:
|
||||
$env: AWS_REGION
|
||||
```
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
id: configuring-ci-cd
|
||||
title: Configuring CI/CD to generate and publish TechDocs sites
|
||||
# prettier-ignore
|
||||
description: Configuring CI/CD to generate and publish TechDocs sites to cloud storage
|
||||
---
|
||||
|
||||
In the [Recommended deployment setup](./architecture.md#recommended-deployment),
|
||||
TechDocs reads the static generated documentation files from a cloud storage
|
||||
bucket (GCS, AWS S3, etc.). The documentation site is generated on the CI/CD
|
||||
workflow associated with the repository containing the documentation files. This
|
||||
document explains the steps needed to generate docs on CI and publish to a cloud
|
||||
storage using [`techdocs-cli`](https://github.com/backstage/techdocs-cli).
|
||||
|
||||
The steps here target all kinds of CI providers (GitHub Actions, CircleCI,
|
||||
Jenkins, etc.). Specific tools for individual providers will also be made
|
||||
available here for simplicity (e.g. a GitHub Actions runner, CircleCI orb,
|
||||
etc.).
|
||||
|
||||
A summary of the instructions below looks like this -
|
||||
|
||||
```sh
|
||||
# This is an example script
|
||||
|
||||
# Prepare
|
||||
REPOSITORY_URL='https://github.com/org/repo'
|
||||
git clone $REPOSITORY_URL
|
||||
cd repo
|
||||
|
||||
# Generate
|
||||
npx @techdocs/cli generate
|
||||
|
||||
# Publish
|
||||
npx @techdocs/cli publish --publisher-type awsS3 --storage-name <bucket/container> --entity <Namespace/Kind/Name>
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
Take a look at
|
||||
[`techdocs-cli` README](https://github.com/backstage/techdocs-cli) for the
|
||||
complete command reference, details, and options.
|
||||
|
||||
## 1. Setup a workflow
|
||||
|
||||
The TechDocs workflow should trigger on CI when any changes are made in the
|
||||
repository containing the documentation files. You can be specific and configure
|
||||
the workflow to be triggered only when files inside the `docs/` directory or
|
||||
`mkdocs.yml` are changed.
|
||||
|
||||
## 2. Prepare step
|
||||
|
||||
The first step on the CI is to clone your documentation source repository in a
|
||||
working directory. This is almost always the first step in most CI workflows.
|
||||
|
||||
On GitHub Actions, you can add a step
|
||||
|
||||
[`- uses: actions@checkout@v2`](https://github.com/actions/checkout).
|
||||
|
||||
On CircleCI, you can add a special
|
||||
[`checkout`](https://circleci.com/docs/2.0/configuration-reference/#checkout)
|
||||
step.
|
||||
|
||||
Eventually we are trying to do a `git clone <https://path/to/docs-repository/>`.
|
||||
|
||||
## 3. Generate step
|
||||
|
||||
Install [`npx`](https://www.npmjs.com/package/npx) to use it for running
|
||||
`techdocs-cli`. Or you can install using `npm install -g @techdocs/cli`.
|
||||
|
||||
We are going to use the
|
||||
[`techdocs-cli generate`](https://github.com/backstage/techdocs-cli#generate-techdocs-site-from-a-documentation-project)
|
||||
command in this step.
|
||||
|
||||
```sh
|
||||
npx @techdocs/cli generate --no-docker --source-dir PATH_TO_REPO --output-dir ./site
|
||||
```
|
||||
|
||||
`PATH_TO_REPO` should be the location in the file path where the prepare step
|
||||
above clones the repository.
|
||||
|
||||
## 4. Publish step
|
||||
|
||||
Depending on your cloud storage provider (AWS, Google Cloud, or Azure), set the
|
||||
necessary authentication environment variables.
|
||||
|
||||
- [Google Cloud authentication](https://cloud.google.com/storage/docs/authentication#libauth)
|
||||
- [AWS authentication](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html)
|
||||
|
||||
And then run the
|
||||
[`techdocs-cli publish`](https://github.com/backstage/techdocs-cli#publish-generated-techdocs-sites)
|
||||
command.
|
||||
|
||||
```sh
|
||||
npx @techdocs/cli publish --publisher-type <awsS3|googleGcs> --storage-name <bucket/container> --entity <namespace/kind/name> --directory ./site
|
||||
```
|
||||
|
||||
The updated TechDocs site built in this workflow is now ready to be served by
|
||||
the TechDocs plugin in your Backstage app.
|
||||
@@ -41,7 +41,7 @@ setup for free.
|
||||
|
||||
### Manually add documentation setup to already existing repository
|
||||
|
||||
Prerequisities:
|
||||
Prerequisites:
|
||||
|
||||
- An existing component
|
||||
[registered in backstage](../software-catalog/index.md#adding-components-to-the-catalog)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: how-to-guides
|
||||
title: TechDocs "HOW TO" guides
|
||||
sidebar_label: "HOW TO" guides
|
||||
description: TechDocs "HOW TO" guides related to TechDocs
|
||||
---
|
||||
|
||||
## How to use URL Reader in TechDocs Prepare step?
|
||||
|
||||
If TechDocs is configured to generate docs, it will first download the
|
||||
repository associated with the `backstage.io/techdocs-ref` annotation defined in
|
||||
the Entity's `catalog-info.yaml` file. This is also called the
|
||||
[Prepare](./concepts.md#techdocs-preparer) step.
|
||||
|
||||
There are two kinds of preparers or two ways of downloading these source files
|
||||
|
||||
- Preparer 1: Doing a `git clone` of the repository (also known as Common Git
|
||||
Preparer)
|
||||
- Preparer 2: Downloading an archive.zip or equivalent of the repository (also
|
||||
known as URL Reader)
|
||||
|
||||
If `backstage.io/techdocs-ref` is equal to any of these -
|
||||
|
||||
1. `github:https://githubhost.com/org/repo`
|
||||
2. `gitlab:https://gitlabhost.com/org/repo`
|
||||
3. `bitbucket:https://bitbuckethost.com/project/repo`
|
||||
4. `azure/api:https://azurehost.com/org/project`
|
||||
|
||||
Then Common Git Preparer will be used i.e. a `git clone`. But the URL Reader is
|
||||
a much faster way to do this step. Convert the `backstage.io/techdocs-ref`
|
||||
values to the following -
|
||||
|
||||
1. `url:https://githubhost.com/org/repo/tree/<branch_name>`
|
||||
2. `url:https://gitlabhost.com/org/repo/tree/<branch_name>`
|
||||
3. `url:https://bitbuckethost.com/project/repo/src/<branch_name>`
|
||||
4. `url:https://azurehost.com/organization/project/_git/repository`
|
||||
|
||||
Note that you can also provide a path to a non-root directory inside the
|
||||
repository which contains the `docs/` directory.
|
||||
|
||||
e.g.
|
||||
`url:https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend/examples/documented-component`
|
||||
|
||||
### Why is URL Reader faster than a git clone?
|
||||
|
||||
URL Reader uses the source code hosting provider to download a zip or tarball of
|
||||
the repository. The archive does not have any git history attached to it. Also
|
||||
it is a compressed file. Hence the file size is significantly smaller than how
|
||||
much data git clone has to transfer.
|
||||
|
||||
Caveat: Currently TechDocs sites built using URL Reader will be cached for 30
|
||||
minutes which means they will not be re-built if new changes are made within 30
|
||||
minutes. This cache invalidation will be replaced by commit timestamp based
|
||||
implementation very soon.
|
||||
@@ -5,6 +5,53 @@ sidebar_label: Troubleshooting
|
||||
description: Troubleshooting for TechDocs
|
||||
---
|
||||
|
||||
- TechDocs will fail to clone your docs if you have a git config which overrides
|
||||
the `https` protocol with `ssh` or something else. Make sure to remove your
|
||||
git config locally when you try TechDocs.
|
||||
## Failure to clone
|
||||
|
||||
TechDocs will fail to clone your docs if you have a git config which overrides
|
||||
the `https` protocol with `ssh` or something else. Make sure to remove your git
|
||||
config locally when you try TechDocs.
|
||||
|
||||
## MkDocs Build Errors
|
||||
|
||||
Using the [TechDocs CLI](https://github.com/backstage/techdocs-cli), you can
|
||||
troubleshoot MkDocs build issues locally. Note this requires you have Docker
|
||||
available to launch images. First, `git clone` the target repository locally,
|
||||
then in the root of the repository, run:
|
||||
|
||||
```
|
||||
npx @techdocs/cli serve
|
||||
```
|
||||
|
||||
For example, if you have forgotten to put an MkDocs configuration file in your
|
||||
repo, the resulting error will be:
|
||||
|
||||
```
|
||||
npx: installed 278 in 9.089s
|
||||
[techdocs-preview-bundle] Running local version of Backstage at http://localhost:3000
|
||||
INFO - Building documentation...
|
||||
|
||||
Config file '/content/mkdocs.yml' does not exist.
|
||||
```
|
||||
|
||||
When it works, a local copy of both Backstage and your site will be launched
|
||||
locally:
|
||||
|
||||
```
|
||||
npx: installed 278 in 9.682s
|
||||
[techdocs-preview-bundle] Running local version of Backstage at http://localhost:3000
|
||||
INFO - Building documentation...
|
||||
WARNING - Config value: 'dev_addr'. Warning: The use of the IP address '0.0.0.0'
|
||||
suggests a production environment or the use of a proxy to connect to the MkDocs
|
||||
server. However, the MkDocs' server is intended for local development purposes only.
|
||||
Please use a third party production-ready server instead.
|
||||
INFO - Cleaning site directory
|
||||
DEBUG - Successfully imported extension module "plantuml_markdown".
|
||||
DEBUG - Successfully loaded extension "plantuml_markdown.PlantUMLMarkdownExtension".
|
||||
INFO - Documentation built in 0.23 seconds
|
||||
[I 210115 19:00:45 server:335] Serving on http://0.0.0.0:8000
|
||||
INFO - Serving on http://0.0.0.0:8000
|
||||
[I 210115 19:00:45 handlers:62] Start watching changes
|
||||
INFO - Start watching changes
|
||||
[I 210115 19:00:45 handlers:64] Start detecting changes
|
||||
INFO - Start detecting changes
|
||||
```
|
||||
|
||||
@@ -30,20 +30,35 @@ techdocs:
|
||||
type: 'googleGcs'
|
||||
```
|
||||
|
||||
**2. GCP (Google Cloud Platform) Project**
|
||||
**2. Create a GCS Bucket**
|
||||
|
||||
Create or choose a dedicated GCP project. Set
|
||||
`techdocs.publisher.googleGcs.projectId` to the project ID.
|
||||
Create a dedicated Google Cloud Storage bucket for TechDocs sites.
|
||||
techdocs-backend will publish documentation to this bucket. TechDocs will fetch
|
||||
files from here to serve documentation in Backstage. Note that the bucket names
|
||||
are globally unique.
|
||||
|
||||
Set the config `techdocs.publisher.googleGcs.bucketName` in your
|
||||
`app-config.yaml` to the name of the bucket you just created.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
googleGcs:
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
```
|
||||
|
||||
**3. Service account API key**
|
||||
**3a. (Recommended) Authentication using environment variable**
|
||||
|
||||
The GCS Node.js client will automatically use the environment variable
|
||||
`GOOGLE_APPLICATION_CREDENTIALS` to authenticate with Google Cloud. It might
|
||||
already be set in Compute Engine, Google Kubernetes Engine, etc. Read
|
||||
https://cloud.google.com/docs/authentication/production for more details.
|
||||
|
||||
**3b. Authentication using app-config.yaml**
|
||||
|
||||
If you do not prefer (3a) and optionally like to use a service account, you can
|
||||
follow these steps.
|
||||
|
||||
Create a new Service Account and a key associated with it. In roles of the
|
||||
service account, use "Storage Admin".
|
||||
@@ -65,31 +80,118 @@ techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json'
|
||||
```
|
||||
|
||||
**4. GCS Bucket**
|
||||
|
||||
Create a dedicated bucket for TechDocs sites. techdocs-backend will publish
|
||||
documentation to this bucket. TechDocs will fetch files from here to serve
|
||||
documentation in Backstage.
|
||||
|
||||
Set the name of the bucket to `techdocs.publisher.googleGcs.bucketName`.
|
||||
Note: If you are finding it difficult to make the file
|
||||
`google_application_credentials.json` available on a server, you could use the
|
||||
file's content and set as an environment variable. And then use
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json'
|
||||
$env: GOOGLE_APPLICATION_CREDENTIALS
|
||||
```
|
||||
|
||||
**4. That's it!**
|
||||
|
||||
Your Backstage app is now ready to use Google Cloud Storage for TechDocs, to
|
||||
store and read the static generated documentation files.
|
||||
|
||||
## Configuring AWS S3 Bucket with TechDocs
|
||||
|
||||
**1. Set `techdocs.publisher.type` config in your `app-config.yaml`**
|
||||
|
||||
Set `techdocs.publisher.type` to `'awsS3'`.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'awsS3'
|
||||
```
|
||||
|
||||
**2. Create an S3 Bucket**
|
||||
|
||||
Create a dedicated AWS S3 bucket for the storage of TechDocs sites.
|
||||
[Refer to the official documentation](https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-bucket.html).
|
||||
|
||||
TechDocs will publish documentation to this bucket and will fetch files from
|
||||
here to serve documentation in Backstage. Note that the bucket names are
|
||||
globally unique.
|
||||
|
||||
Set the config `techdocs.publisher.awsS3.bucketName` in your `app-config.yaml`
|
||||
to the name of the bucket you just created.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'awsS3'
|
||||
awsS3:
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
```
|
||||
|
||||
**5. That's it!**
|
||||
**3a. (Recommended) Setup authentication the AWS way, using environment
|
||||
variables**
|
||||
|
||||
Your Backstage app is now ready to use Google Cloud Storage for TechDocs, to
|
||||
store the static generated documentation files.
|
||||
You should follow the
|
||||
[AWS security best practices guide for authentication](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html).
|
||||
|
||||
If the environment variables
|
||||
|
||||
- `AWS_ACCESS_KEY_ID`
|
||||
- `AWS_SECRET_ACCESS_KEY`
|
||||
- `AWS_REGION`
|
||||
|
||||
are set and can be used to access the bucket you created in step 2, they will be
|
||||
used by the AWS SDK v3 Node.js client for authentication.
|
||||
[Refer to the official documentation.](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html)
|
||||
|
||||
If the environment variables are missing, the AWS SDK tries to read the
|
||||
`~/.aws/credentials` file for credentials.
|
||||
[Refer to the official documentation.](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-shared.html)
|
||||
|
||||
Note that the region of the bucket has to be set for the AWS SDK to work.
|
||||
[See this](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html).
|
||||
|
||||
**3b. Authentication using app-config.yaml**
|
||||
|
||||
AWS credentials and region can be provided to the AWS SDK via `app-config.yaml`.
|
||||
If the configs below are present, they will be used over existing `AWS_*`
|
||||
environment variables and the `~/.aws/credentials` config file.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'awsS3'
|
||||
awsS3:
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
region:
|
||||
$env: AWS_REGION
|
||||
credentials:
|
||||
accessKeyId:
|
||||
$env: AWS_ACCESS_KEY_ID
|
||||
secretAccessKey:
|
||||
$env: AWS_SECRET_ACCESS_KEY
|
||||
```
|
||||
|
||||
Refer to the
|
||||
[official AWS documentation for obtaining the credentials](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-your-credentials.html).
|
||||
|
||||
Note: If you are using Amazon EC2 instance to deploy Backstage, you do not need
|
||||
to obtain the access keys separately. They can be made available in the
|
||||
environment automatically by defining appropriate IAM role with access to the
|
||||
bucket. Read more
|
||||
[here](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html#use-roles).
|
||||
|
||||
**4. That's it!**
|
||||
|
||||
Your Backstage app is now ready to use AWS S3 for TechDocs, to store and read
|
||||
the static generated documentation files. When you start the backend of the app,
|
||||
you should be able to see
|
||||
`techdocs info Successfully connected to the AWS S3 bucket` in the logs.
|
||||
|
||||
@@ -74,6 +74,22 @@ those plugins in your backend. This is because the transformation of backend
|
||||
module tree stops whenever a non-local package is encountered, and from that
|
||||
point node will `require` packages directly for that entire module subtree.
|
||||
|
||||
Type checking can also have issues when linking in external packages, since the
|
||||
linked in packages will use the types in the external project and dependency
|
||||
version mismatches between the two projects may cause errors. To fix any of
|
||||
those errors you need to sync versions of the dependencies in the two projects.
|
||||
A simple way to do this can be to copy over `yarn.lock` from the external
|
||||
project and run `yarn install`, although this is quite intrusive and can cause
|
||||
other issues in existing projects, so use this method with care. It can often be
|
||||
best to simply ignore the type errors, as app serving will work just fine
|
||||
anyway.
|
||||
|
||||
Another issue with type checking is that the incremental type cache doesn't
|
||||
invalidate correctly for the linked in packages, causing type checking to not
|
||||
reflect changes made to types. You can work around this by either setting
|
||||
`compilerOptions.incremental = false` in `tsconfig.json`, or by deleting the
|
||||
types cache folder `dist-types` before running `yarn tsc`.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
The create app command doesn't always work as expected, this is a collection of
|
||||
|
||||
@@ -13,10 +13,10 @@ Run the following commands if you have Docker environment
|
||||
```bash
|
||||
$ yarn install
|
||||
$ yarn docker-build
|
||||
$ docker run --rm -it -p 7000:7000 -e APP_ENV=production -e NODE_ENV=development example-backend:latest
|
||||
$ docker run --rm -it -p 7000:7000 -e NODE_ENV=development example-backend:latest
|
||||
```
|
||||
|
||||
Then open http://localhost/ on your browser.
|
||||
Then open http://localhost:7000 on your browser.
|
||||
|
||||
## Heroku
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: development-environment
|
||||
title: Development Environment
|
||||
description: Documentation on how to get set up for doing development on
|
||||
the Backstage repository
|
||||
# prettier-ignore
|
||||
description: Documentation on how to get set up for doing development on the Backstage repository
|
||||
---
|
||||
|
||||
This section describes how to get set up for doing development on the Backstage
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
id: glossary
|
||||
title: Backstage Glossary
|
||||
# prettier-ignore
|
||||
description: List of all the terms, abbreviations, and phrases used in Backstage, together with their explanations.
|
||||
---
|
||||
|
||||
The Backstage Glossary lists all the terms, abbreviations, and phrases used in
|
||||
Backstage, together with their explanations. We encourage you to use the
|
||||
terminology below for clarity and consistency when discussing Backstage.
|
||||
|
||||
### Backstage User Profiles
|
||||
|
||||
There are three main user profiles for Backstage: the integrator, the
|
||||
contributor, and the software engineer.
|
||||
|
||||
| Term | Explanation |
|
||||
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Integrator | The **integrator** hosts the Backstage app and configures which plugins are available to use in the app. |
|
||||
| Contributor | The **contributor** adds functionality to the app by writing plugins. |
|
||||
| Software Engineer | The **software engineer** uses the app's functionality and interacts with its plugins. In practice, this profile covers the various roles that help deliver software, from the Software Engineer themselves, to Designers, Data Scientists, Product Owners, Engineering Managers, etc. |
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: adopting
|
||||
title: Strategies for adopting
|
||||
description: Documentation on some general best practices that have been key
|
||||
to Backstage's success inside Spotify
|
||||
# prettier-ignore
|
||||
description: Documentation on some general best practices that have been key to Backstage's success inside Spotify
|
||||
---
|
||||
|
||||
This document outlines some general best practices that have been key to
|
||||
|
||||
@@ -185,17 +185,6 @@ separate Docker images.
|
||||
|
||||

|
||||
|
||||
The frontend container can be built with a provided command.
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
yarn tsc
|
||||
yarn run docker-build:app
|
||||
```
|
||||
|
||||
Running this will simply generate a Docker container containing the contents of
|
||||
the UIs `dist` directory.
|
||||
|
||||
The backend container can be built by running the following command:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: background
|
||||
title: The Spotify Story
|
||||
description: Backstage was born out of necessity at Spotify. We found that as we grew, our
|
||||
infrastructure was becoming more fragmented, our engineers less productive.
|
||||
# prettier-ignore
|
||||
description: Backstage was born out of necessity at Spotify. We found that as we grew, our infrastructure was becoming more fragmented, our engineers less productive.
|
||||
---
|
||||
|
||||
Backstage was born out of necessity at Spotify. We found that as we grew, our
|
||||
|
||||
@@ -8,9 +8,9 @@ description: Roadmap of Backstage Project
|
||||
|
||||
> Backstage is currently under rapid development. This means that you can expect
|
||||
> APIs and features to evolve. It is also recommended that teams who adopt
|
||||
> Backstage today upgrade their installation as new
|
||||
> [releases](https://github.com/backstage/backstage/releases) become available,
|
||||
> as Backwards compatibility is not yet guaranteed.
|
||||
> Backstage today [upgrade their installation](../cli/commands.md#versionsbump)
|
||||
> as new [releases](https://github.com/backstage/backstage/releases) become
|
||||
> available, as Backwards compatibility is not yet guaranteed.
|
||||
|
||||
## Phases
|
||||
|
||||
@@ -57,8 +57,10 @@ guidelines to get started.
|
||||
see and manage their services running in K8s, regardless if that's locally, in
|
||||
AWS, GCS, Azure, or elsewhere.
|
||||
|
||||
- **Global search** - Extend the basic search functionality currently available
|
||||
in the Backstage Service Catalog to become a global search experience.
|
||||
- **[Search platform](../features/search/README.md)** - Evolve the basic search
|
||||
functionality currently available into a platform that **a)** enables search
|
||||
across the software catalog, TechDocs, and any other information exposed by
|
||||
plugins, and **b)** supports a variety of search engine technologies.
|
||||
|
||||
- **[Software Templates V2](https://github.com/backstage/backstage/issues/2771)** -
|
||||
Expand the templates to make the steps more composable by adding the ability
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
id: stability-index
|
||||
title: Stability Index
|
||||
description:
|
||||
An overview of the commitment to stability for different parts of the
|
||||
Backstage codebase.
|
||||
# prettier-ignore
|
||||
description: An overview of the commitment to stability for different parts of the Backstage codebase.
|
||||
---
|
||||
|
||||
## Overview
|
||||
@@ -291,7 +290,7 @@ Stability: `1`. There are plans to rework parts of the Processor interface.
|
||||
|
||||
### `catalog-graphql` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/catalog-graphql/)
|
||||
|
||||
Provides the catalog schema and resolvers for the graphql backend.
|
||||
Provides the catalog schema and resolvers for the GraphQL backend.
|
||||
|
||||
Stability: `0`. Under heavy development and subject to change.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: vision
|
||||
title: Vision
|
||||
description: Goal is to provide engineers with the best developer experience in
|
||||
the world
|
||||
# prettier-ignore
|
||||
description: Goal is to provide engineers with the best developer experience in the world
|
||||
---
|
||||
|
||||
Our goal is to provide engineers with the best developer experience in the
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
id: what-is-backstage
|
||||
title: What is Backstage?
|
||||
description: Backstage is an open platform for building developer portals.
|
||||
Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure
|
||||
# prettier-ignore
|
||||
description: Backstage is an open platform for building developer portals. Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure
|
||||
---
|
||||
|
||||

|
||||
|
||||
[Backstage](https://backstage.io/) is an open platform for building developer
|
||||
portals. Powered by a centralized service catalog, Backstage restores order to
|
||||
your microservices and infrastructure. So your product teams can ship
|
||||
your microservices and infrastructure and enables your product teams to ship
|
||||
high-quality code quickly — without compromising autonomy.
|
||||
|
||||
Backstage unifies all your infrastructure tooling, services, and documentation
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: call-existing-api
|
||||
title: Call Existing API
|
||||
description: Describes the various options that Backstage frontend plugins have,
|
||||
in communicating with service APIs that already exist
|
||||
# prettier-ignore
|
||||
description: Describes the various options that Backstage frontend plugins have, in communicating with service APIs that already exist
|
||||
---
|
||||
|
||||
This article describes the various options that Backstage frontend plugins have,
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
---
|
||||
id: composability
|
||||
title: Composability System Migration
|
||||
# prettier-ignore
|
||||
description: Documentation and migration instructions for new composability APIs.
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This page describes the new composability system that was recently introduced in
|
||||
Backstage, and it does so from the perspective of the existing patterns and
|
||||
APIs. As the new system is solidified and existing code is ported, this page
|
||||
will be removed and replaced with a more direct description of the composability
|
||||
system. For now, the primary purpose of this documentation is to aid in the
|
||||
migration of existing plugins, but it does cover the migration of apps as well.
|
||||
|
||||
The core principle of the new composability system is that plugins should have
|
||||
clear boundaries and connections. It should isolate crashes within a plugin, but
|
||||
allow navigation between them. It should allow for plugins to be loaded only
|
||||
when needed, and enable plugins to provide extension points for other plugins to
|
||||
build upon. The composability system is also built with an app-first mindset,
|
||||
prioritizing simplicity and clarity in the app over that in the plugins and core
|
||||
APIs.
|
||||
|
||||
The new composability system isn't a single new API surface. It is a collection
|
||||
of patterns, primitives, new APIs, and old APIs used in new ways. At the core is
|
||||
the new concept of extensions, which are exported by plugins for use in the app.
|
||||
There is also a new primitive called component data, which assists in the
|
||||
conversion to a more declarative app. The `RouteRef`s now have a clear purpose
|
||||
as well, and can be used route to pages in a flexible way.
|
||||
|
||||
## New Concepts
|
||||
|
||||
This section is a brief look into all the new and updated concepts that were put
|
||||
in place to support the new composability system.
|
||||
|
||||
### Component Data
|
||||
|
||||
Component data is a new composability primitive that is introduced as a way to
|
||||
provide a new data dimension for React components. Data is attached to React
|
||||
components using a key, and is then readable from any JSX elements created with
|
||||
those components, using the same key, as illustrated by the following example:
|
||||
|
||||
```tsx
|
||||
const MyComponent = () => <h1>This is my component</h1>;
|
||||
attachComponentData(MyComponent, 'my.data', 5);
|
||||
|
||||
const element = <MyComponent />;
|
||||
const myData = getComponentData(element, 'my.data');
|
||||
// myData === 5
|
||||
```
|
||||
|
||||
The purpose of component data is to provide a method for embedding data that can
|
||||
be inspected before rendering elements. Element inspection is a pattern that is
|
||||
quite common among React libraries, and used for example by `react-router` and
|
||||
`material-ui` to discover properties of the child elements before rendering.
|
||||
Although in those libraries only the element type and props are typically
|
||||
inspected, while our component data adds more structured access and simplifies
|
||||
evolution by allowing for multiple different versions of a piece of data to be
|
||||
used and interpreted at once.
|
||||
|
||||
The initial use-case for component data is to support route and plugin discovery
|
||||
through elements in the app. Through this we allow for the React element tree in
|
||||
the app to be the source of truth, both for which plugins are used, as well as
|
||||
all top-level plugin routes in the app. The use of component data is not limited
|
||||
to these use-cases though, as it can be used as a primitive to create new
|
||||
abstractions as well.
|
||||
|
||||
### Extensions
|
||||
|
||||
Extensions are what plugins export for use in an app. Most typically they are
|
||||
React components, but in practice they can be any kind of JavaScript value. They
|
||||
are created using `create*Extension` functions, and wrapped with
|
||||
`plugin.provide()` in order to create the actual exported extension.
|
||||
|
||||
The extension type is a simple one:
|
||||
|
||||
```ts
|
||||
export type Extension<T> = {
|
||||
expose(plugin: BackstagePlugin<any, any>): T;
|
||||
};
|
||||
```
|
||||
|
||||
The power of extensions comes from the ability of various actors to hook into
|
||||
their usage. The creation and plugin wrapping is controlled by whoever owns the
|
||||
creation function, the Backstage core is able to hook into the process of
|
||||
exposing the extension outside the plugin, and in the end the app controls the
|
||||
usage of the extension.
|
||||
|
||||
The Backstage core API currently provides two different types of extension
|
||||
creators, `createComponentExtension`, and `createRoutableExtension`. Component
|
||||
extensions are plain React component with no particular requirements, for
|
||||
example a card for an entity overview page. The component will be exported more
|
||||
or less as is, but is wrapped to provide things like an error boundary, lazy
|
||||
loading, and a plugin context.
|
||||
|
||||
Routable extensions build on top of component extensions and are used for any
|
||||
component that should be rendered at a specific route path, such as top-level
|
||||
pages or entity page tab content. When creating a routable extension you need to
|
||||
supply a `RouteRef` as `mountPoint`. The mount point will be the handle of the
|
||||
component for the outside world, and is used by other components and plugins
|
||||
that wish to link to the routable component.
|
||||
|
||||
As of now there are only two extension creation functions, but it is possible to
|
||||
add more of them in the future, both in the core library and in plugins that
|
||||
wish to provide an extension point for other plugins to build upon. Extensions
|
||||
are also not tied to React, and can both be used to model generic JavaScript
|
||||
concepts, as well as potentially bridge to rendering libraries and web
|
||||
frameworks other than React.
|
||||
|
||||
### Extensions from a Plugin's Point of View
|
||||
|
||||
Extensions are one of the primary methods to traverse the plugin boundary, and
|
||||
the way that plugins provide concrete content for use within an app. They
|
||||
replace existing component export concepts such as `Router` or `*Card`s for
|
||||
display on entity overview pages.
|
||||
|
||||
It is recommended to create the exported extensions either in the top-level
|
||||
`plugin.ts` file, or in a dedicated `extensions.ts` (or `.tsx`) file. That file
|
||||
should not contain the bulk of the implementation though, and in fact, if the
|
||||
extension is a React component it is recommended to lazy-load the actual
|
||||
component. Component extensions support lazy loading out of the box using the
|
||||
`lazy` component declaration, for example:
|
||||
|
||||
```ts
|
||||
export const EntityFooCard = plugin.provide(
|
||||
createComponentExtension({
|
||||
component: {
|
||||
lazy: () => import('./components/FooCard').then(m => m.FooCard),
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Routable extensions even enforce lazy loading, as it is the only way to provide
|
||||
a component:
|
||||
|
||||
```ts
|
||||
export const FooPage = plugin.provide(
|
||||
createRoutableExtension({
|
||||
component: () => import('./components/FooPage').then(m => m.FooPage),
|
||||
mountPoint: fooPageRouteRef,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
### Using Extensions in an App
|
||||
|
||||
Right now all extensions are modelled as React components. The usage of these
|
||||
extension is like regular usage of any React components, with one important
|
||||
difference. Extensions must all be part of a single React element tree spanning
|
||||
from the root `AppProvider`.
|
||||
|
||||
For example, the following app code does **NOT** work:
|
||||
|
||||
```tsx
|
||||
const AppRoutes = () => (
|
||||
<Routes>
|
||||
<Route path="/foo" element={<FooPage />} />
|
||||
<Route path="/bar" element={<BarPage />} />
|
||||
</Routes>
|
||||
);
|
||||
|
||||
const App = () => (
|
||||
<AppProvider>
|
||||
<AppRouter>
|
||||
<Root>
|
||||
<AppRoutes />
|
||||
</Root>
|
||||
</AppRouter>
|
||||
</AppProvider>
|
||||
);
|
||||
```
|
||||
|
||||
But in this case it is simple to fix! Simply be sure to not create any
|
||||
intermediate components in the app, for example like this:
|
||||
|
||||
```tsx
|
||||
const appRoutes = (
|
||||
<Routes>
|
||||
<Route path="/foo" element={<FooPage />} />
|
||||
<Route path="/bar" element={<BarPage />} />
|
||||
</Routes>
|
||||
);
|
||||
|
||||
const App = () => (
|
||||
<AppProvider>
|
||||
<AppRouter>
|
||||
<Root>{appRoutes}</Root>
|
||||
</AppRouter>
|
||||
</AppProvider>
|
||||
);
|
||||
```
|
||||
|
||||
### New Routing System
|
||||
|
||||
A big piece of what is enabled by moving over to this new composability system
|
||||
is to make `RouteRef`s useful. The `RouteRef`s no longer have their own path, in
|
||||
fact the only required parameter is currently a `title`. Instead of assigning a
|
||||
path to each `RouteRef` and possibly overriding these paths in the app, the
|
||||
concrete `path` for each `RouteRef` is discovered based on the element tree in
|
||||
the app. Let's consider the following example:
|
||||
|
||||
```tsx
|
||||
const appRoutes = (
|
||||
<Routes>
|
||||
<Route path="/foo" element={<FooPage />} />
|
||||
<Route path="/bar" element={<BarPage />} />
|
||||
</Routes>
|
||||
);
|
||||
```
|
||||
|
||||
We'll assume that `FooPage` and `BarPage` are routable extensions, exported by
|
||||
the `fooPlugin` and `barPlugin` respectively. Since the `FooPage` is a routable
|
||||
extension it has a `RouteRef` assigned as its mount point, which we'll refer to
|
||||
as `fooPageRouteRef`.
|
||||
|
||||
Given the above example, the `fooPageRouteRef` will be associated with the
|
||||
`'/foo'` route. The path is no longer accessible via the `path` property of the
|
||||
`RouteRef` though, as the routing structure is tied to the app's react tree. We
|
||||
instead use the new `useRouteRef` hook if we want to create a concrete link to
|
||||
the page. The `useRouteRef` hook takes a single `RouteRef` as its only
|
||||
parameter, and returns a function that is called to create the URL. For example
|
||||
like this:
|
||||
|
||||
```tsx
|
||||
const MyComponent = () => {
|
||||
const fooRoute = useRouteRef(fooPageRouteRef);
|
||||
return <a href={fooRoute()}>Link to Foo</a>;
|
||||
};
|
||||
```
|
||||
|
||||
Now let's assume that we want to link from the `BarPage` to the `FooPage`.
|
||||
Before the introduction of the new composability system, we would do this by
|
||||
importing the `fooPageRouteRef` exported by the `fooPlugin`. This created an
|
||||
unnecessary dependency on the plugin, and also provided little flexibility in
|
||||
allowing the app to tie plugins together, with the links instead being dictated
|
||||
by the plugins themselves. To solve this, we introduce `ExternalRouteRef`s. Much
|
||||
like regular route references, they can be passed to `useRouteRef` to create
|
||||
concrete URLs, but they can not be used as mount points in routable component
|
||||
and instead have to be associated with a target route using route bindings in
|
||||
the app.
|
||||
|
||||
We create a new `ExternalRouteRef` inside the `barPlugin`, using a neutral name
|
||||
that describes its role in the plugin rather than a specific plugin page that it
|
||||
might be linking to, allowing the app to decide the final target. If the
|
||||
`BarPage` for example wants to link to an external page in the header, it might
|
||||
declare an `ExternalRouteRef` similar to this:
|
||||
|
||||
```ts
|
||||
const headerLinkRouteRef = createExternalRouteRef();
|
||||
```
|
||||
|
||||
### Binding External Routes in the App
|
||||
|
||||
The association of external routes is controlled by the app. Each
|
||||
`ExternalRouteRef` of a plugin should be bound to an actual `RouteRef`, usually
|
||||
from another plugin. The binding process happens once at app startup, and is
|
||||
then used through the lifetime of the app to help resolve concrete route paths.
|
||||
|
||||
Using the above example of the `BarPage` linking to the `FooPage`, we might do
|
||||
something like this in the app:
|
||||
|
||||
```ts
|
||||
createApp({
|
||||
bindRoutes({ bind }) {
|
||||
bind(barPlugin.externalRoutes, {
|
||||
headerLink: fooPlugin.routes.root,
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Given the above binding, using `useRouteRef(headerLinkRouteRef)` within the
|
||||
`barPlugin` will let us create a link to whatever path the `FooPage` is mounted
|
||||
at.
|
||||
|
||||
Note that we are not importing and using the `RouteRef`s directly in the app,
|
||||
and instead rely on the plugin instance to access routes of the plugins. This is
|
||||
a new convention that was introduced to provide better namespacing and
|
||||
discoverability of routes, as well as reduce the number of separate exports from
|
||||
each plugin package. The route references would be supplied to `createPlugin`
|
||||
like this:
|
||||
|
||||
```ts
|
||||
// In foo-plugin
|
||||
export const fooPlugin = createPlugin({
|
||||
routes: {
|
||||
root: fooPageRouteRef,
|
||||
},
|
||||
...
|
||||
})
|
||||
|
||||
// In bar-plugin
|
||||
export const barPlugin = createPlugin({
|
||||
externalRoutes: {
|
||||
headerLink: headerLinkRouteRef,
|
||||
},
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
Also note that you almost always want to create the route references themselves
|
||||
in a different file than the one that creates the plugin instance, for example a
|
||||
top-level `routes.ts`. This is to avoid circular imports when you use the route
|
||||
references from other parts of the same plugin.
|
||||
|
||||
### Parameterized Routes
|
||||
|
||||
A new addition to `RouteRef`s is the possibility of adding named and typed
|
||||
parameters. Parameters are declared at creation, and will enforce presence of
|
||||
the parameters in the path in the app, and require them as a parameter when
|
||||
using `useRouteRef`.
|
||||
|
||||
The following is an example of creation and usage of a parameterized route:
|
||||
|
||||
```tsx
|
||||
// Creation of a parameterized route
|
||||
const myRouteRef = createRouteRef({
|
||||
title: 'My Named Route',
|
||||
params: ['name']
|
||||
})
|
||||
|
||||
// In the app, where MyPage is a routable extension with myRouteRef set as mountPoint
|
||||
<Route path='/my-page/:name' element={<MyPage />}/>
|
||||
|
||||
// Usage within a component
|
||||
const myRoute = useRouteRef(myRouteRef)
|
||||
return (
|
||||
<div>
|
||||
<a href={myRoute({name: 'a'})}>A</a>
|
||||
<a href={myRoute({name: 'b'})}>B</a>
|
||||
</div>
|
||||
)
|
||||
```
|
||||
|
||||
It is currently not possible to have parameterized `ExternalRouteRef`s, or to
|
||||
bind an external route to a parameterized route, although this may be added in
|
||||
the future if needed.
|
||||
|
||||
### New Catalog Components
|
||||
|
||||
The established pattern for selecting what plugins should be available on each
|
||||
catalog page is to use custom components in the app, with logic embedded in the
|
||||
render function. Typically this takes form as a component that either receives
|
||||
the entity via props or uses the `useEntity` hook to retrieve the selected
|
||||
entity. A `switch` or `if` / `else if` chain is then used to select what
|
||||
children should be rendered based on information in the entity.
|
||||
|
||||
This pattern will no longer work with the new composability system, and in
|
||||
general is very difficult to build any form of declarative model around, as it
|
||||
depends on runtime execution. To help replace existing code, a new
|
||||
`EntitySwitch` component has been added to the `@backstage/catalog` plugin,
|
||||
which grabs the selected entity from a context, and selects at most one element
|
||||
to render using a list of `EntitySwitch.Case` children.
|
||||
|
||||
For example, if you want all entities of kind `"Template"` to be rendered with a
|
||||
`MyTemplate` component, and all other entities to be rendered with a `MyOther`
|
||||
component, you would do the following:
|
||||
|
||||
```tsx
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('template')}>
|
||||
<MyTemplate />
|
||||
</EntitySwitch.Case>
|
||||
|
||||
<EntitySwitch.Case>
|
||||
<MyTemplate />
|
||||
</EntitySwitch.Case>
|
||||
</EntitySwitch>
|
||||
|
||||
// Shorter form if desired:
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('template')} children={<MyTemplate />}/>
|
||||
<EntitySwitch.Case children={<MyTemplate />}/>
|
||||
</EntitySwitch>
|
||||
```
|
||||
|
||||
The `EntitySwitch` component will render the children of the first
|
||||
`EntitySwitch.Case` that returns `true` when the selected entity is passed to
|
||||
the function of the `if` prop. If none of the cases match, no children will be
|
||||
rendered, and if a case doesn't specify an `if` filter function, it will always
|
||||
match. The `if` property is simply a function of the type
|
||||
`(entity: Entity) => boolean`, for example, `isKind` can be implemented like
|
||||
this:
|
||||
|
||||
```ts
|
||||
function isKind(kind: string) {
|
||||
return (entity: Entity) => entity.kind.toLowerCase() === kind.toLowerCase();
|
||||
}
|
||||
```
|
||||
|
||||
The `@backstage/catalog` plugin provides a couple of built-in conditions,
|
||||
`isKind`, `isComponentType`, and `isNamespace`.
|
||||
|
||||
In addition to the `EntitySwitch` component, the catalog plugin also exports a
|
||||
new `EntityLayout` component. It is a tweaked version and replacement for the
|
||||
`EntityPageLayout` component, and is introduced more in depth in the app
|
||||
migration section below.
|
||||
|
||||
## Porting Existing Plugins
|
||||
|
||||
There are a couple of high-level steps to porting an existing plugin to the new
|
||||
composability system:
|
||||
|
||||
- Remove usage of `router.addRoute` or `router.registerRoute` within
|
||||
`createPlugin`, and export the page components as routable extensions instead.
|
||||
- Switch any `Router` export to instead be a routable extension.
|
||||
- Change any plain component exports, such as catalog overview cards, to be
|
||||
component extensions.
|
||||
- Stop exporting `RouteRef`s and instead pass them to `createPlugin`.
|
||||
- Stop accepting `RouteRef`s as props or importing them from other plugins,
|
||||
instead create an `ExternalRouteRef` as a replacement, and pass it to
|
||||
`createPlugin.`
|
||||
- Rename any other exported symbols according to the naming pattern table below.
|
||||
|
||||
Note that removing the existing exports and configuration is a breaking change
|
||||
in any plugin. If backwards compatibility is needed the existing code be
|
||||
deprecated while making the new additions, to then be removed at a later point.
|
||||
|
||||
### Naming Patterns
|
||||
|
||||
Many export naming patterns have been changed to avoid import aliases and to
|
||||
clarify intent. Refer to the following table to formulate the new name:
|
||||
|
||||
| Description | Existing Pattern | New Pattern | Examples |
|
||||
| -------------------- | -------------------------- | --------------- | ---------------------------------------------- |
|
||||
| Top-level Pages | Router | \*Page | CatalogIndexPage, SettingsPage, LighthousePage |
|
||||
| Entity Tab Content | Router | Entity\*Content | EntityJenkinsContent, EntityKubernetesContent |
|
||||
| Entity Overview Card | \*Card | Entity\*Card | EntitySentryCard, EntityPagerDutyCard |
|
||||
| Entity Conditional | isPluginApplicableToEntity | is\*Available | isPagerDutyAvailable, isJenkinsAvailable |
|
||||
| Plugin Instance | plugin | \*Plugin | jenkinsPlugin, catalogPlugin |
|
||||
|
||||
## Porting Existing Apps
|
||||
|
||||
The first step of porting any app is to replace the root `Routes` component with
|
||||
`FlatRoutes` from `@backstage/core`. As opposed to the `Routes` component,
|
||||
`FlatRoutes` only considers the first level of `Route` components in its
|
||||
children, and provides any additional children to the outlet of the route. It
|
||||
also removes the need to append `"/*"` to paths, as it is added automatically.
|
||||
|
||||
```diff
|
||||
const AppRoutes = () => (
|
||||
- <Routes>
|
||||
+ <FlatRoutes>
|
||||
...
|
||||
- <Route path="/docs/*" element={<DocsRouter />} />
|
||||
+ <Route path="/docs" element={<DocsRouter />} />
|
||||
...
|
||||
- </Routes>
|
||||
+ </FlatRoutes>
|
||||
);
|
||||
```
|
||||
|
||||
The next step should be to switch from using `EntityPageLayout` to
|
||||
`EntityLayout`, as this can also be done without waiting for plugins to be
|
||||
ported. You should also replace the top-level `Router` from the catalog plugin
|
||||
with the separate `CatalogIndexPage` and `CatalogEntityPage` extensions that
|
||||
have been added to the catalog:
|
||||
|
||||
```diff
|
||||
-<Route
|
||||
- path={`${catalogRouteRef.path}/*`}
|
||||
- element={<CatalogRouter EntityPage={EntityPage} />}
|
||||
-/>
|
||||
+<Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
+<Route
|
||||
+ path="/catalog/:namespace/:kind/:name"
|
||||
+ element={<CatalogEntityPage />}
|
||||
+>
|
||||
+ <EntityPage />
|
||||
+</Route>
|
||||
```
|
||||
|
||||
At that point you should flatten out the element tree as much as possible in the
|
||||
app, removing any intermediate components. At the top level this should usually
|
||||
be straightforward, but when reaching the catalog entity pages you may need to
|
||||
wait for some plugins to be migrated. This is because it is no longer possible
|
||||
to pass in the selected entity through component props, and it should be picked
|
||||
up from context inside the plugin instead. See the sections below for how to
|
||||
carry out migrations of some common entity page patterns.
|
||||
|
||||
Once the app element tree doesn't contain any intermediate components, and all
|
||||
plugin imports have been switched to extensions rather than plain components,
|
||||
the app has been fully ported.
|
||||
|
||||
### Switching from EntityPageLayout to EntityLayout
|
||||
|
||||
The existing `EntityPageLayout` is replaced by the new `EntityLayout` component,
|
||||
which has a slightly different pattern for expressing the contents and paths.
|
||||
|
||||
Porting from the old to the new API is just a matter of moving some things
|
||||
around. For example, given the following existing code:
|
||||
|
||||
```tsx
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<ComponentOverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/sentry"
|
||||
title="Sentry"
|
||||
element={<SentryRouter entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/kubernetes/*"
|
||||
title="Kubernetes"
|
||||
element={<KubernetesRouter entity={entity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
```
|
||||
|
||||
It would be ported to this:
|
||||
|
||||
```tsx
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="Overview">
|
||||
<ComponentOverviewContent entity={entity} />
|
||||
</EntityLayout.Route>
|
||||
|
||||
<EntityLayout.Route path="/sentry" title="Sentry">
|
||||
<SentryRouter entity={entity} />
|
||||
</EntityLayout.Route>
|
||||
|
||||
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
|
||||
<KubernetesRouter entity={entity} />
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
```
|
||||
|
||||
In addition to the renaming, the `element` prop has been moved to `children`.
|
||||
Also note that the `/*` suffix has been removed from the `"/kubernetes"` path,
|
||||
as it's now added automatically.
|
||||
|
||||
Usage of the `EntityLayout` component is required to be able to properly
|
||||
discover routes, and so it is required to apply this change before you can start
|
||||
using routable entity content extensions from plugins.
|
||||
|
||||
### Porting Entity Pages
|
||||
|
||||
The established pattern in the app is to use custom components in order to
|
||||
select what plugin components to render for a given entity. The new
|
||||
`EntitySwitch` component introduced above is what is intended to replace this
|
||||
pattern, now that the entire app needs to be rendered as a single element tree.
|
||||
For example, given the following existing code:
|
||||
|
||||
```tsx
|
||||
export const EntityPage = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
switch (entity?.kind?.toLowerCase()) {
|
||||
case 'component':
|
||||
return <ComponentEntityPage entity={entity} />;
|
||||
case 'api':
|
||||
return <ApiEntityPage entity={entity} />;
|
||||
case 'group':
|
||||
return <GroupEntityPage entity={entity} />;
|
||||
case 'user':
|
||||
return <UserEntityPage entity={entity} />;
|
||||
default:
|
||||
return <DefaultEntityPage entity={entity} />;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
It would be migrated to this:
|
||||
|
||||
```tsx
|
||||
export const entityPage = (
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('component')} children={componentPage} />
|
||||
<EntitySwitch.Case if={isKind('api')} children={apiPage} />
|
||||
<EntitySwitch.Case if={isKind('group')} children={groupPage} />
|
||||
<EntitySwitch.Case if={isKind('user')} children={userPage} />
|
||||
<EntitySwitch.Case children={defaultPage} />
|
||||
</EntitySwitch>
|
||||
);
|
||||
```
|
||||
|
||||
Note that for example `<ComponentEntityPage ... />` has been changed to simply
|
||||
`componentPage`, that is because just like the `EntityPage` component, the
|
||||
`ComponentEntityPage` also needs to be ported to be an element rather a
|
||||
component in a similar way.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Using GitHub Apps for Backend Authentication
|
||||
|
||||
Backstage can be configured to use GitHub Apps for backend authentication. This
|
||||
comes with advantages such as higher rate limits and that Backstage can act as
|
||||
an application instead of a user or bot account.
|
||||
|
||||
It also provides a much clearer and better authorization model as a opposed to
|
||||
the OAuth apps and their respective scopes.
|
||||
|
||||
## Caveats
|
||||
|
||||
- It's not possible to have multiple Backstage GitHub Apps installed in the same
|
||||
GitHub organization, to be handled by Backstage. We currently don't check
|
||||
through all the registered GitHub Apps to see which ones are installed for a
|
||||
particular repository. We only respect global Organization installs right now.
|
||||
- App permissions is not managed by Backstage. They're created with some simple
|
||||
default permissions which you are free to change as you need, but you will
|
||||
need to update them in the GitHub web console, not in Backstage right now. The
|
||||
permissions that are defaulted are `metadata:read` and `contents:read`.
|
||||
- The created GitHub App is private by default, this is most likely what you
|
||||
want for github.com but it's recommended to make your application public for
|
||||
GitHub Enterprise in order to share application across your GHE organizations.
|
||||
|
||||
A GitHub app created with `backstage-cli create-github-app` will have read
|
||||
access by default. You have to manually update the GitHub App settings in GitHub
|
||||
to grant the app more permissions if needed.
|
||||
|
||||
### Using the CLI (public GitHub only)
|
||||
|
||||
You can use the `backstage-cli` to create GitHub App' using a manifest file that
|
||||
we provide. This gives us a way to automate some of the work required to create
|
||||
a GitHub app.
|
||||
|
||||
You can read more about the `backstage-cli create-github-app` method
|
||||
[here](../cli/commands.md#create-github-app)
|
||||
|
||||
Once you've gone through the CLI command, it should produce a `yaml` file in the
|
||||
root of the project which you can then use as an `include` in your
|
||||
`app-config.yaml`. You can go ahead and skip to
|
||||
[here](#including-in-integrations-config) if you've got to this part.
|
||||
|
||||
### GitHub Enterprise
|
||||
|
||||
You have to create the GitHub Application manually using these
|
||||
[instructions](https://docs.github.com/en/free-pro-team@latest/developers/apps/creating-a-github-app)
|
||||
as GitHub Enterprise does not support creation of apps from manifests.
|
||||
|
||||
Once the application is created you have to generate a private key for the
|
||||
application it in a `yaml` file.
|
||||
|
||||
The yaml file must include the following information. Please note that the
|
||||
indentation for the `privateKey` is required.
|
||||
|
||||
```yaml
|
||||
appId: 1
|
||||
clientId: client id
|
||||
clientSecret: client secret
|
||||
webhookSecret: webhook secret
|
||||
privateKey: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
...Key content...
|
||||
-----END RSA PRIVATE KEY-----
|
||||
```
|
||||
|
||||
### Including in Integrations Config
|
||||
|
||||
Once the credentials are stored in a yaml file generated by `create-github-app`
|
||||
or manually by following the [GitHub Enterprise](#gitHub-enterprise)
|
||||
instructions, they can be included in the `app-config.yaml` under the
|
||||
`integrations` section.
|
||||
|
||||
Please note that the credentials file is highly sensitive and should NOT be
|
||||
checked into any kind of version control. Instead use your preferred secure
|
||||
method of distributing secrets.
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
github:
|
||||
- host: github.com
|
||||
apps:
|
||||
- $include: example-backstage-app-credentials.yaml
|
||||
```
|
||||
@@ -54,13 +54,4 @@ addRoute(
|
||||
Component: ComponentType<any>,
|
||||
options?: RouteOptions,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* @deprecated See the `addRoute` method
|
||||
*/
|
||||
registerRoute(
|
||||
path: RoutePath,
|
||||
Component: ComponentType<any>,
|
||||
options?: RouteOptions,
|
||||
): void;
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ description: Documentation on Publishing npm packages
|
||||
## npm
|
||||
|
||||
npm packages are published through CI/CD in the
|
||||
[.github/workflows/master.yml](https://github.com/backstage/backstage/blob/master/.github/workflows/master.yml)
|
||||
[`.github/workflows/master.yml`](https://github.com/backstage/backstage/blob/master/.github/workflows/master.yml)
|
||||
workflow. Every commit that is merged to master will be checked for new versions
|
||||
of all public packages, and any new versions will automatically be published to
|
||||
npm.
|
||||
|
||||
@@ -16,15 +16,15 @@ frameworks and libraries like [Mocha](https://mochajs.org/),
|
||||
|
||||
Running all tests:
|
||||
|
||||
yarn test-react
|
||||
yarn test
|
||||
|
||||
Running an individual test (e.g. `MyComponent.test.js`):
|
||||
|
||||
yarn test-react MyComponent
|
||||
yarn test MyComponent
|
||||
|
||||
To run both `MyComponent.test.js` and `MyControl.test.js` suite of tests:
|
||||
|
||||
yarn test-react MyCo
|
||||
yarn test MyCo
|
||||
|
||||
Note: if `console.logs` are not appearing, run only the individual test you are
|
||||
working on.
|
||||
@@ -52,12 +52,12 @@ render React components.
|
||||
|
||||
TODO.
|
||||
|
||||
# Writing Unit Tests
|
||||
## Writing Unit Tests
|
||||
|
||||
The following principles are good guides for determining if you are writing high
|
||||
quality frontend unit tests.
|
||||
|
||||
## Bad Unit Test Principle
|
||||
### Bad Unit Test Principle
|
||||
|
||||
> No unit test is better than a bad one.
|
||||
|
||||
@@ -69,7 +69,7 @@ Writing a poor unit test:
|
||||
- Adds to future work by requiring updates to the unit test for irrelevant code
|
||||
changes.
|
||||
|
||||
## Input/Output Principle
|
||||
### Input/Output Principle
|
||||
|
||||
> A unit test verifies an output matches an expected input.
|
||||
|
||||
@@ -77,7 +77,7 @@ For backend, this would be that when you provide configuration X, then the
|
||||
object responds with Y. For frontend, this would be that when you provide
|
||||
properties X to a component, then the visual functionality responds with Y.
|
||||
|
||||
## Blackbox Principle
|
||||
### Blackbox Principle
|
||||
|
||||
> A good unit test does not tell the object how it should do its job but should
|
||||
> only compare inputs to outputs.
|
||||
@@ -86,7 +86,7 @@ Consider a unit test for a form. A good unit test would not test the order of
|
||||
the form fields. Instead, it would verify that the inputs to the form fields
|
||||
lead to a certain backend call when submit is clicked.
|
||||
|
||||
## Scalability Principle
|
||||
### Scalability Principle
|
||||
|
||||
> Unit test quality is directly proportionate to how much code can change
|
||||
> without having to touch the unit test.
|
||||
@@ -97,7 +97,7 @@ to the code, you have to update the unit test. A good unit test suite allows a
|
||||
lot of flexibility in _how_ the code is written so that future refactoring can
|
||||
occur without having to touch the original unit tests.
|
||||
|
||||
## Increasing Complexity Principle
|
||||
### Increasing Complexity Principle
|
||||
|
||||
> The ordering of unit tests in a suite should proceed from least specific to
|
||||
> most specific.
|
||||
@@ -116,7 +116,7 @@ throwing an error saying that output was incorrect will lead the next developer
|
||||
into thinking they may have broken the entire functionality of the object rather
|
||||
than simply letting them know they had an invalid input.
|
||||
|
||||
## Broken Functionality Principle
|
||||
### Broken Functionality Principle
|
||||
|
||||
> Generally, a unit test should not test exactly how the output appears, it
|
||||
> should test that the functionality has an expected _general_ response to an
|
||||
@@ -131,7 +131,7 @@ test a slightly different color on the button the unit test will break. A better
|
||||
unit test would verify that the button's CSS classname is assigned properly on
|
||||
hover or test for something completely different.
|
||||
|
||||
## Example: Loading Indicator
|
||||
### Example: Loading Indicator
|
||||
|
||||
A classic unit test on frontends is verifying a loading indicator displays when
|
||||
a backend request is being made.
|
||||
@@ -192,11 +192,14 @@ returns a result or displays an error or console message, like so:
|
||||
|
||||
**`StringUtil ellipsis`**
|
||||
|
||||
export function ellipsis(text, maxLength, midCharIx = 0, ellipsis = '...') {
|
||||
// Do something blackbox. We should not care about the internals, only inputs and outputs.
|
||||
...
|
||||
return someFinalValue;
|
||||
}
|
||||
```js
|
||||
export function ellipsis(text, maxLength, midCharIx = 0, ellipsis = '...') {
|
||||
// Do something blackbox. We should not care about the internals,
|
||||
// only inputs and outputs.
|
||||
...
|
||||
return someFinalValue;
|
||||
}
|
||||
```
|
||||
|
||||
There are four things to test for in a utility function:
|
||||
|
||||
@@ -207,30 +210,36 @@ There are four things to test for in a utility function:
|
||||
|
||||
> Handle Invalid Input (handle thrown errors):
|
||||
|
||||
it('Throws an error on improper arguments', () => {
|
||||
expect(() => {
|
||||
ellipsis();
|
||||
}).toThrowError('Expected \'text\' to be defined');
|
||||
});
|
||||
```js
|
||||
it('Throws an error on improper arguments', () => {
|
||||
expect(() => {
|
||||
ellipsis();
|
||||
}).toThrowError("Expected 'text' to be defined");
|
||||
});
|
||||
```
|
||||
|
||||
> Verify default input arguments:
|
||||
|
||||
it('Works with defaults', () => {
|
||||
expect(ellipsis('Hello world', 3)).toBe('Hel...');
|
||||
expect(ellipsis('', 3)).toBe('');
|
||||
expect(ellipsis('H', 3)).toBe('H');
|
||||
expect(ellipsis('Hello', 5)).toBe('Hello');
|
||||
});
|
||||
```js
|
||||
it('Works with defaults', () => {
|
||||
expect(ellipsis('Hello world', 3)).toBe('Hel...');
|
||||
expect(ellipsis('', 3)).toBe('');
|
||||
expect(ellipsis('H', 3)).toBe('H');
|
||||
expect(ellipsis('Hello', 5)).toBe('Hello');
|
||||
});
|
||||
```
|
||||
|
||||
> Verify output for expected input arguments:
|
||||
|
||||
This is especially true for edge cases!
|
||||
|
||||
it('Works with midCharIx', () => {
|
||||
expect(ellipsis('Hello world', 3, 6)).toBe('...o w...');
|
||||
expect(ellipsis('', 3, 6)).toBe('');
|
||||
expect(ellipsis('Backstage is amazing', 4, 10)).toBe('...e is...');
|
||||
});
|
||||
```js
|
||||
it('Works with midCharIx', () => {
|
||||
expect(ellipsis('Hello world', 3, 6)).toBe('...o w...');
|
||||
expect(ellipsis('', 3, 6)).toBe('');
|
||||
expect(ellipsis('Backstage is amazing', 4, 10)).toBe('...e is...');
|
||||
});
|
||||
```
|
||||
|
||||
## Non-React Classes
|
||||
|
||||
@@ -372,4 +381,4 @@ IDE.
|
||||
In most cases, we have found that using `console.log` works well.
|
||||
|
||||
Note: if your console.logs are not being displayed, focus your specific unit
|
||||
test from the command line by running them like so `yarn test-react MyTest`.
|
||||
test from the command line by running them like so `yarn test MyTest`.
|
||||
|
||||
@@ -15,15 +15,6 @@ addRoute(
|
||||
Component: ComponentType<any>,
|
||||
options?: RouteOptions,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* @deprecated See the `addRoute` method
|
||||
*/
|
||||
registerRoute(
|
||||
path: RoutePath,
|
||||
Component: ComponentType<any>,
|
||||
options?: RouteOptions,
|
||||
): void;
|
||||
```
|
||||
|
||||
## RouteRef
|
||||
|
||||
@@ -29,7 +29,7 @@ These types are part of the API declaration, but may not be unique to this API.
|
||||
|
||||
### Error
|
||||
|
||||
Mirrors the javascript Error class, for the purpose of providing documentation
|
||||
Mirrors the JavaScript Error class, for the purpose of providing documentation
|
||||
and optional fields.
|
||||
|
||||
<pre>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: project-structure
|
||||
title: Backstage Project Structure
|
||||
description:
|
||||
Introduction to files and folders in the Backstage Project repository
|
||||
# prettier-ignore
|
||||
description: Introduction to files and folders in the Backstage Project repository
|
||||
---
|
||||
|
||||
Backstage is a complex project, and the GitHub repository contains many
|
||||
@@ -32,10 +32,6 @@ the code.
|
||||
better control over our `yarn.lock` file and hopefully avoid problems due to
|
||||
yarn versioning differences.
|
||||
|
||||
- [`docker/`](https://github.com/backstage/backstage/tree/master/docker) - Files
|
||||
related to our root Dockerfile. We are planning to refactor this, so expect
|
||||
this folder to be moved in the future.
|
||||
|
||||
- [`contrib/`](https://github.com/backstage/backstage/tree/master/contrib) -
|
||||
Collection of examples or resources provided by the community. We really
|
||||
appreciate contributions in here and encourage them being kept up to date.
|
||||
|
||||
@@ -3,20 +3,18 @@ id: quickstart-app-auth
|
||||
title: Monorepo App Setup With Authentication
|
||||
---
|
||||
|
||||
###### September 15th 2020 - @backstage/create-app - v0.1.1-alpha.21
|
||||
###### January 8th 2021 - @backstage/create-app - v0.4.5
|
||||
|
||||
<br />
|
||||
|
||||
> This document takes you through setting up a Backstage app that runs in your
|
||||
> own environment. It starts with a skeleton install and verifying of the
|
||||
> monorepo's functionality. Next, GitHub authentication is added and tested.
|
||||
> monorepo's functionality. Next, authentication is added and tested.
|
||||
>
|
||||
> This document assumes you have Node.js 12 active along with Yarn and Python.
|
||||
> Please note, that at the time of this writing, the current version is
|
||||
> 0.1.1-alpha.21. This guide can still be used with future versions, just,
|
||||
> verify as you go. If you run into issues, you can compare your setup with mine
|
||||
> here >
|
||||
> [simple-backstage-app](https://github.com/johnson-jesse/simple-backstage-app).
|
||||
> This document assumes you have Node.js 12 or 14 active along with Yarn and
|
||||
> Python. Please note, that at the time of this writing, the current version is
|
||||
> v0.4.5. This guide can still be used with future versions, just, verify as you
|
||||
> go.
|
||||
|
||||
# The Skeleton Application
|
||||
|
||||
@@ -55,7 +53,17 @@ guest. Let's fix that now and add auth.
|
||||
|
||||
# The Auth Configuration
|
||||
|
||||
1. Open `app-config.yaml` and change it as follows
|
||||
A default Backstage installation includes multiple authentication providers out
|
||||
of the box. The steps to enable new authentication providers in Backstage are
|
||||
very similar to each other, the biggest difference is usually configuring the
|
||||
external authentication provider. Please see a subset of possible providers and
|
||||
instructions to integrate them below. Steps 1 & 2 are described separately for
|
||||
each provider and steps beyond that are common for all.
|
||||
|
||||
<details><summary>GitHub</summary>
|
||||
<p>
|
||||
|
||||
### 1. Open `app-config.yaml` and change it as follows
|
||||
|
||||
_from:_
|
||||
|
||||
@@ -75,23 +83,229 @@ auth:
|
||||
$env: AUTH_GITHUB_CLIENT_ID
|
||||
clientSecret:
|
||||
$env: AUTH_GITHUB_CLIENT_SECRET
|
||||
## uncomment the following three lines if using enterprise
|
||||
## uncomment the following two lines if using enterprise
|
||||
# enterpriseInstanceUrl:
|
||||
# $env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
|
||||
```
|
||||
|
||||
2. Set environment variables in whatever fashion is easiest for you. I chose to
|
||||
add mine to my `.zshrc` profile.
|
||||
### 2. Generate a GitHub client ID and secret
|
||||
|
||||
- Log into http://github.com
|
||||
- Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth
|
||||
App)[https://github.com/settings/applications/new]
|
||||
- Set Homepage URL = `http://localhost:3000`
|
||||
- Set Callback URL = `http://localhost:7000/api/auth/github`
|
||||
- Click [Register application]
|
||||
- On the next page, copy and paste your new Client ID and Client Secret to
|
||||
environment variables defined in the `app-config.yaml` file,
|
||||
`AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET`
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details><summary>GitLab</summary>
|
||||
<p>
|
||||
|
||||
### 1. Open `app-config.yaml` and change it as follows
|
||||
|
||||
_from:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers: {}
|
||||
```
|
||||
|
||||
_to:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
gitlab:
|
||||
development:
|
||||
clientId:
|
||||
$env: AUTH_GITLAB_CLIENT_ID
|
||||
clientSecret:
|
||||
$env: AUTH_GITLAB_CLIENT_SECRET
|
||||
audience: https://gitlab.com # Or your self-hosted GitLab instance URL
|
||||
```
|
||||
|
||||
### 2. Generate a GitLab Application client ID and secret
|
||||
|
||||
- Log into GitLab
|
||||
- Navigate to (Profile > Settings >
|
||||
Applications)[https://gitlab.com/-/profile/applications]
|
||||
- Name your application
|
||||
- Set Callback URL = `http://localhost:7000/api/auth/gitlab/handler/frame`
|
||||
- Select the following values:
|
||||
- `read_user` (Read the authenticated user's personal information)
|
||||
- `read_repository` (Allows read-only access to the repository)
|
||||
- `write_repository` (Allows read-write access to the repository)
|
||||
- `openid` (Authenticate using OpenID Connect)
|
||||
- `profile` (Allows read-only access to the user's personal information using
|
||||
OpenID Connect)
|
||||
- `email` (Allows read-only access to the user's primary email address using
|
||||
OpenID Connect)
|
||||
- Click [Save application]
|
||||
- On the next page, copy and paste your new Application ID and Secret to
|
||||
environment variables defined in the `app-config.yaml` file,
|
||||
`AUTH_GITLAB_CLIENT_ID` & `AUTH_GITLAB_CLIENT_SECRET`
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details><summary>Google</summary>
|
||||
<p>
|
||||
|
||||
### 1. Open `app-config.yaml` and change it as follows
|
||||
|
||||
_from:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers: {}
|
||||
```
|
||||
|
||||
_to:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
google:
|
||||
development:
|
||||
clientId:
|
||||
$env: AUTH_GOOGLE_CLIENT_ID
|
||||
clientSecret:
|
||||
$env: AUTH_GOOGLE_CLIENT_SECRET
|
||||
```
|
||||
|
||||
### 2. Generate Google Credentials in Google Cloud console
|
||||
|
||||
- Log into https://console.cloud.google.com
|
||||
- Select or create a new project from the dropdown on the top bar
|
||||
- Navigate to (APIs & Services >
|
||||
Credentials)[https://console.cloud.google.com/apis/credentials]
|
||||
- Click Create Credentials and select [OAuth client ID]
|
||||
- Select Web Application as the application type
|
||||
- Add new Authorised JavaScript origin = `http://localhost:3000`
|
||||
- Add new Authorised redirect URI =
|
||||
`http://localhost:7000/api/auth/google/handler/frame`
|
||||
- Click [Save application]
|
||||
- Google should display a modal with your Client ID and Secret. Copy and paste
|
||||
those to environment variables defined in the `app-config.yaml` file,
|
||||
`AUTH_GOOGLE_CLIENT_ID` & `AUTH_GOOGLE_CLIENT_SECRET`
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details><summary>Microsoft</summary>
|
||||
<p>
|
||||
|
||||
### 1. Open `app-config.yaml` and change it as follows
|
||||
|
||||
_from:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers: {}
|
||||
```
|
||||
|
||||
_to:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
microsoft:
|
||||
development:
|
||||
clientId:
|
||||
$env: AUTH_MICROSOFT_CLIENT_ID
|
||||
clientSecret:
|
||||
$env: AUTH_MICROSOFT_CLIENT_SECRET
|
||||
tenantId:
|
||||
$env: AUTH_MICROSOFT_TENANT_ID
|
||||
```
|
||||
|
||||
### 2. Create a Microsoft App Registration in Microsoft Portal
|
||||
|
||||
- Log into https://portal.azure.com
|
||||
- Navigate to (Azure Active Directory > App
|
||||
Registrations)[https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps]
|
||||
- Create a New Registration
|
||||
- Add new Redirect URI = `http://localhost:3000`
|
||||
- Add new Authorised redirect URI =
|
||||
`http://localhost:7000/api/auth/microsoft/handler/frame`
|
||||
- Click [Save application]
|
||||
- Set environment variable `AUTH_MICROSOFT_CLIENT_ID` from
|
||||
`Application (client) Id` displayed on the directory page
|
||||
- Set environment variable `AUTH_MICROSOFT_TENANT_ID` from
|
||||
`Directory (tenant) ID` displayed on the directory page
|
||||
- Navigate to Certificates & Secrets section and click [Create a new secret]
|
||||
- Set environment variable `AUTH_MICROSOFT_CLIENT_SECRET` from the `value` field
|
||||
created.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details><summary>Auth0</summary>
|
||||
<p>
|
||||
|
||||
### 1. Open `app-config.yaml` and change it as follows
|
||||
|
||||
_from:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers: {}
|
||||
```
|
||||
|
||||
_to:_
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
auth0:
|
||||
development:
|
||||
clientId:
|
||||
$env: AUTH_AUTH0_CLIENT_ID
|
||||
clientSecret:
|
||||
$env: AUTH_AUTH0_CLIENT_SECRET
|
||||
domain:
|
||||
$env: AUTH_AUTH0_DOMAIN_ID
|
||||
```
|
||||
|
||||
### 2. Create an Auth0 application in the Auth0 management console
|
||||
|
||||
- Log into https://manage.auth0.com/dashboard/
|
||||
- Navigate to Applications
|
||||
- Create a New Application
|
||||
- Select Single Page Web Application
|
||||
- Go to Settings tab
|
||||
- Add new line to Allowed Callback URLs =
|
||||
`http://localhost:7000/api/auth/auth0/handler/frame`
|
||||
- Click [Save Changes]
|
||||
- Set environment variables displayed on the Basic Information page
|
||||
- `AUTH_AUTH0_CLIENT_ID` from `Client ID` displayed on Auth0 application page
|
||||
- `AUTH_AUTH0_CLIENT_SECRET` from `Client Secret` displayed on Auth0
|
||||
application page
|
||||
- `AUTH_AUTH0_DOMAIN_ID` from `Domain` displayed on Auth0 application page
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### 3. Set environment variables in whatever fashion is easiest for you. I chose to
|
||||
|
||||
add mine to my `.zshrc` profile.
|
||||
|
||||
```zsh
|
||||
# For macOS Catalina & Z Shell
|
||||
# ------ simple-backstage-app GitHub
|
||||
#
|
||||
# (Change the name of the environment variables based on your auth setup above)
|
||||
export AUTH_GITHUB_CLIENT_ID=xxx
|
||||
export AUTH_GITHUB_CLIENT_SECRET=xxx
|
||||
# export AUTH_GITHUB_ENTERPRISE_INSTANCE_URL=https://github.{MY_BIZ}.com
|
||||
```
|
||||
|
||||
3. And of course I need to source that file.
|
||||
### 4. And of course I need to source that file.
|
||||
|
||||
```zsh
|
||||
# Loading the new variables
|
||||
@@ -107,26 +321,28 @@ export AUTH_GITHUB_CLIENT_SECRET=xxx
|
||||
> ...
|
||||
```
|
||||
|
||||
4. The values to replace `xxx` above come from your oauth app setup.
|
||||
### 5. Open and change _root > packages > app > src >_ `App.tsx` to use correct
|
||||
|
||||
```
|
||||
> Log into http://github.com
|
||||
> Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth App)[https://github.com/settings/applications/new]
|
||||
> Set Homepage URL = http://localhost:3000
|
||||
> Set Callback URL = http://localhost:7000/api/auth/github
|
||||
> Click [Register application]
|
||||
> On the next page, copy and paste your new Client ID and Client Secret to the environment variables above, `AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET`
|
||||
> Don't forget to `source` that profile file again if necessary.
|
||||
```
|
||||
|
||||
5. Open and change _root > packages > app > src >_`App.tsx` as follows
|
||||
authentication provider reference
|
||||
|
||||
```tsx
|
||||
// Add the following imports to the existing list from core
|
||||
import { githubAuthApiRef, SignInPage } from '@backstage/core';
|
||||
```
|
||||
|
||||
6. In the same file, change the createApp function as follows
|
||||
Modify the imported reference based on the authentication method you selected
|
||||
above:
|
||||
|
||||
| Auth Provider | Import Name |
|
||||
| ------------- | ------------------- |
|
||||
| GitHub | githubAuthApiRef |
|
||||
| GitLab | gitlabAuthApiRef |
|
||||
| Google | googleAuthApiRef |
|
||||
| Microsoft | microsoftAuthApiRef |
|
||||
| Auth0 | auth0AuthApiRef |
|
||||
|
||||
### 6. In the same file, modify createApp
|
||||
|
||||
Remember to modify the provider information based on the table above.
|
||||
|
||||
```tsx
|
||||
const app = createApp({
|
||||
@@ -153,12 +369,18 @@ const app = createApp({
|
||||
});
|
||||
```
|
||||
|
||||
7. Start the backend and frontend as before
|
||||
After finishing setting up one (or multiple) authentication providers defined
|
||||
above you can start the backend and frontend as before
|
||||
|
||||
When the browser loads, you should be presented with a login page for GitHub.
|
||||
Login as usual with your GitHub account. If this is your first time, you will be
|
||||
asked to authorize and then are redirected to the catalog page if all is well.
|
||||
|
||||
For more information you can clone
|
||||
[the backstage-auth-example repository](https://github.com/RoadieHQ/backstage-auth-example).
|
||||
Each authentication setting is set up there on a branch named after the
|
||||
authentication provider.
|
||||
|
||||
# Where to go from here
|
||||
|
||||
> You're probably eager to write your first custom plugin. Follow this next
|
||||
|
||||