Merge branch 'backstage:master' into master
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-codescene': patch
|
||||
---
|
||||
|
||||
Updated Readme document in codescene plugin
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Fix custom http resolvers for AsyncAPI widget.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-compat-api': patch
|
||||
---
|
||||
|
||||
Make `convertLegacyApp` wrap discovered routes with `compatWrapper`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Adding support for removing file from git index
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-sonarqube-backend': patch
|
||||
---
|
||||
|
||||
Updated README
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings': patch
|
||||
---
|
||||
|
||||
add user-settings declarative integration core nav item
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Add permission check to Register Existing API button
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Bumped create-app version.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-common': patch
|
||||
---
|
||||
|
||||
Updated Template.v1beta3.schema.json, added a missing "presentation" field
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
---
|
||||
|
||||
Fix for a step with no properties
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-openapi': patch
|
||||
---
|
||||
|
||||
Add support for the new backend system.
|
||||
|
||||
A new backend module for the catalog backend
|
||||
was added and exported as `default`.
|
||||
|
||||
You can use it with the new backend system like
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-catalog-backend-module-openapi'));
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket': patch
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-octopus-deploy': patch
|
||||
---
|
||||
|
||||
added install path and fixed import on plugin-octopus-deploy
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Accepts sub route refs on the new `createPlugin` routes map.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-events-backend-module-bitbucket-cloud': patch
|
||||
'@backstage/plugin-events-backend-module-gerrit': patch
|
||||
'@backstage/plugin-events-backend-module-azure': patch
|
||||
---
|
||||
|
||||
Add default exports for the new backend system and documentation.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Renamed the `app/router` extension to `app/root`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-test-utils': patch
|
||||
---
|
||||
|
||||
Updates to reflect the `app/router` extension having been renamed to `app/root`.
|
||||
+16
-1
@@ -266,17 +266,32 @@
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-mice-give",
|
||||
"brave-queens-crash",
|
||||
"brown-planes-sort",
|
||||
"chatty-rivers-hope",
|
||||
"chilled-seahorses-clean",
|
||||
"chilled-zebras-wash",
|
||||
"create-app-1703547661",
|
||||
"create-app-1704804195",
|
||||
"curvy-dingos-jump",
|
||||
"fast-tables-hammer",
|
||||
"friendly-horses-kneel",
|
||||
"funny-rings-fry",
|
||||
"gold-pianos-worry",
|
||||
"happy-forks-jam",
|
||||
"hip-dancers-pay",
|
||||
"large-poets-buy",
|
||||
"lazy-teachers-walk",
|
||||
"many-peaches-dress",
|
||||
"new-plants-sort",
|
||||
"orange-planets-suffer",
|
||||
"quiet-oranges-bake",
|
||||
"renovate-126fde4",
|
||||
"renovate-91133b2",
|
||||
"renovate-9647667",
|
||||
"rotten-tools-clean"
|
||||
"rotten-tools-clean",
|
||||
"sour-taxis-rush",
|
||||
"stale-hairs-sparkle",
|
||||
"tricky-pans-explain"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-test-utils': patch
|
||||
'@backstage/backend-plugin-api': patch
|
||||
'@backstage/backend-dev-utils': patch
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
Updated README to reflect release status
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/plugin-home-react': patch
|
||||
'@backstage/plugin-home': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Updated dependency `@rjsf/utils` to `5.15.1`.
|
||||
Updated dependency `@rjsf/core` to `5.15.1`.
|
||||
Updated dependency `@rjsf/material-ui` to `5.15.1`.
|
||||
Updated dependency `@rjsf/validator-ajv8` to `5.15.1`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-events-backend-module-aws-sqs': patch
|
||||
---
|
||||
|
||||
Fix errors when deleting SQS messages:
|
||||
|
||||
- If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client.
|
||||
- If zero failures were returned from the SQS client during deletion, skip error logging.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-test-utils': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Added `elements` and `wrappers` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension` and `createAppRootWrapperExtension` extension creator, respectively, to conveniently create such extensions.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
Attaching extensions to an input that does not exist is now a warning rather than an error.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Minor internal refactor
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-events-backend-module-aws-sqs': patch
|
||||
'@backstage/plugin-events-backend': patch
|
||||
---
|
||||
|
||||
Add documentation on how to install the plugins with the new backend system.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-permission-backend': patch
|
||||
'@backstage/plugin-permission-common': patch
|
||||
'@backstage/plugin-permission-react': patch
|
||||
'@backstage/plugin-permission-node': patch
|
||||
---
|
||||
|
||||
Updated README
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-linguist': patch
|
||||
---
|
||||
|
||||
Added alpha support for the New Frontend System (Declarative Integration)
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-app-visualizer': minor
|
||||
---
|
||||
|
||||
Initial release of the app visualizer plugin.
|
||||
@@ -13,29 +13,33 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📜 Description'
|
||||
description: 'A clear and concise description of what the bug is. It bugs out when ...'
|
||||
description: 'A clear and concise description of what the bug is.'
|
||||
placeholder: 'It bugs out when ...'
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👍 Expected behavior'
|
||||
description: 'What did you think should happen? It should ...'
|
||||
description: 'What did you think should happen?'
|
||||
placeholder: 'It should ...'
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👎 Actual Behavior with Screenshots'
|
||||
description: 'What did actually happen? Add screenshots, if applicable. It actually ...'
|
||||
description: 'What did actually happen? Add screenshots, if applicable.'
|
||||
placeholder: 'It actually ...'
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👟 Reproduction steps'
|
||||
description: 'How do you trigger this bug? Please walk us through it step by step. Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.'
|
||||
placeholder: "\n
|
||||
description: 'How do you trigger this bug? Please walk us through it step by step.'
|
||||
placeholder:
|
||||
"Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.\n
|
||||
1. Go to '...'\n
|
||||
2. Click on '....'\n
|
||||
3. Scroll down to '....'"
|
||||
@@ -45,14 +49,17 @@ body:
|
||||
required: false
|
||||
attributes:
|
||||
label: '📃 Provide the context for the Bug.'
|
||||
description: 'How has this issue affected you? What are you trying to accomplish? Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
|
||||
description: 'How has this issue affected you? What are you trying to accomplish?'
|
||||
placeholder: 'Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
|
||||
- type: textarea
|
||||
id: environment
|
||||
validations:
|
||||
required: false
|
||||
attributes:
|
||||
label: '🖥️ Your Environment'
|
||||
description: 'Always provide output of `yarn backstage-cli info`; provide browser information when applicable. Include as many relevant details about the environment you experienced the bug in.'
|
||||
description: 'Provide Browser Information
|
||||
Provide Output of `yarn backstage-cli info`'
|
||||
placeholder: 'Include as many relevant details about the environment you experienced the bug in.'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
|
||||
@@ -14,6 +14,7 @@ body:
|
||||
attributes:
|
||||
label: '🔖 Feature description'
|
||||
description: 'A clear and concise description of what the feature is.'
|
||||
placeholder: 'You should add ...'
|
||||
- type: textarea
|
||||
id: context
|
||||
validations:
|
||||
@@ -21,11 +22,13 @@ body:
|
||||
attributes:
|
||||
label: '🎤 Context'
|
||||
description: 'Please explain why this feature should be implemented and how it would be used. Add examples, if applicable.'
|
||||
placeholder: 'In my use-case, ...'
|
||||
- type: textarea
|
||||
id: implementation
|
||||
attributes:
|
||||
label: '✌️ Possible Implementation'
|
||||
description: 'A clear and concise description of what you want to happen. Not obligatory, but ideas as to the implementation of the addition or change.'
|
||||
description: 'A clear and concise description of what you want to happen.'
|
||||
placeholder: 'Not obligatory, but ideas as to the implementation of the addition or change'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
|
||||
@@ -14,16 +14,19 @@ body:
|
||||
attributes:
|
||||
label: '🔖 Summary'
|
||||
description: 'Provide a general summary of the plugin and how it should work'
|
||||
placeholder: 'You should add ...'
|
||||
- type: textarea
|
||||
id: website
|
||||
attributes:
|
||||
label: '🌐 Project website (if applicable)'
|
||||
description: 'Add a link to the open source project or product this plugin will integrate with, if existing'
|
||||
placeholder: 'Website Link is ...'
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: '✌️ Context'
|
||||
description: 'A clear and concise description about the Plugin and any additional context.'
|
||||
description: 'A clear and concise description about the Plugin.'
|
||||
placeholder: 'Providing additional context'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
|
||||
@@ -13,24 +13,28 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 Need'
|
||||
description: "Let us know why are you proposing this change. The problem we're trying to address and the benefits/impact we expect to get from this are ..."
|
||||
description: 'Let us know why are you proposing this change'
|
||||
placeholder: 'The problem we’re trying to address and the benefits/impact we expect to get from this are ...'
|
||||
- type: textarea
|
||||
id: proposal
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🎉 Proposal'
|
||||
description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback. Take special care in this section to describe any implications on data privacy or security.'
|
||||
description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback.'
|
||||
placeholder: 'Take special care in this section to describe any implications on data privacy or security.'
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: '〽️ Alternatives'
|
||||
description: 'What alternatives to the proposed solution were considered? What criteria/data was used to discard these?'
|
||||
description: 'What alternatives to the proposed solution were considered?'
|
||||
placeholder: 'What criteria/data was used to discard these?'
|
||||
- type: textarea
|
||||
id: risk
|
||||
attributes:
|
||||
label: '❌ Risks'
|
||||
description: 'What other things happening could conflict or compete (for example for resources) with the proposal? What risk are there and how do we plan to handle them?'
|
||||
description: 'What other things happening could conflict or compete (for example for resources) with the proposal?'
|
||||
placeholder: 'What risk are there and how do we plan to handle them?'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
|
||||
@@ -6,34 +6,37 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We value your time and efforts to submit this UX Component form. 🙏
|
||||
We value your time and efforts to submit this RFC form. 🙏
|
||||
- type: textarea
|
||||
id: ux-general
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 General'
|
||||
description: |
|
||||
'Write a nice note to the community requesting the creation of a new component. Include an image of your component. Bonus points for a GIF!'
|
||||
description: 'Write a nice note to the community requesting the creation of a new component.'
|
||||
placeholder: 'Include an image of your component. Bonus points for a GIF!'
|
||||
- type: textarea
|
||||
id: usage
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '💻 Usage'
|
||||
description: "Tell us what's the point of this component/pattern is. How does it help? How should it work? Any rules?"
|
||||
description: "Tell us what's the point of this component/pattern is."
|
||||
placeholder: 'How does it help? How should it work? Any rules?'
|
||||
- type: textarea
|
||||
id: specs
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📐 Specs'
|
||||
description: "Include images that detail the redlines for your component. Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
|
||||
description: 'Include images that detail the redlines for your component.'
|
||||
placeholder: "Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
|
||||
- type: textarea
|
||||
id: future
|
||||
attributes:
|
||||
label: '🔮 Future'
|
||||
description: 'List out any upcoming, exciting functionality for this component.'
|
||||
placeholder: 'The component will have ...'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
|
||||
@@ -30,5 +30,6 @@ jobs:
|
||||
with:
|
||||
# This also contains --config=.github/vale/config.ini ... :/
|
||||
files: '${{ steps.generate.outputs.args }}'
|
||||
version: 2.30.0 # TODO: migrate to v3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- uses: actions/setup-python@v4.7.1
|
||||
- uses: actions/setup-python@v4.8.0
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: setup python
|
||||
uses: actions/setup-python@v4.7.1
|
||||
uses: actions/setup-python@v4.8.0
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
---
|
||||
title: Backstage Notifications System
|
||||
status: provisional
|
||||
authors:
|
||||
- Rugvip
|
||||
project-areas:
|
||||
- core
|
||||
creation-date: 2023-01-12
|
||||
---
|
||||
|
||||
# BEP: Backstage Notifications System
|
||||
|
||||
[**Discussion Issue**](https://github.com/backstage/backstage/issues/22213)
|
||||
|
||||
- [Summary](#summary)
|
||||
- [Motivation](#motivation)
|
||||
- [Goals](#goals)
|
||||
- [Non-Goals](#non-goals)
|
||||
- [Proposal](#proposal)
|
||||
- [Design Details](#design-details)
|
||||
- [Release Plan](#release-plan)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Alternatives](#alternatives)
|
||||
|
||||
## Summary
|
||||
|
||||
The Backstage Notifications System provides a way for Backstage plugins to send notifications to users. The notifications are displayed in the Backstage frontend UI, but future extensions can allow them to be sent via external channels such as email. The system includes a push mechanism to make sure that users receive notifications immediately, as well as persistence of notification history and read status.
|
||||
|
||||
## Motivation
|
||||
|
||||
Support for notifications is an old and common features request. See [#639](https://github.com/backstage/backstage/issues/639) and [#10652](https://github.com/backstage/backstage/issues/10652). There are also initiatives to implement notifications in [#20312](https://github.com/backstage/backstage/issues/20312) as well as the underlying infrastructure pieces, for example [#17997](https://github.com/backstage/backstage/issues/17997).
|
||||
|
||||
This proposal assumes that further motivation for a notifications system as a whole is not needed. The focus is instead on the specific goals of an initial notifications system, and generally aiming to address the need to coordinate this work.
|
||||
|
||||
### Goals
|
||||
|
||||
We aim to build a system that would provide support for the following type of notifications, as listed in [#10652](https://github.com/backstage/backstage/issues/10652):
|
||||
|
||||
- System-wide announcements or alerts
|
||||
- Notifications for component owners (e.g. build failure, successful deployment, new vulnerabilities)
|
||||
- Notifications for individuals (e.g. updates you have subscribed to, new required training courses)
|
||||
- Notifications pertaining to a particular entity in the catalog (a given notification might apply to an entity and the owning team)
|
||||
|
||||
Initially we only target a single way to send notifications: via a REST API call to the notifications backend, which in turn also provides an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services).
|
||||
|
||||
The notifications system will need to support scaled deployments, where multiple backend instances may be deployed.
|
||||
|
||||
In the future we aim to provide an extensible system that can be customized to send notifications to users via other channels. Notifications can be captured and processed in-band in order to trigger custom behavior such as sending an email. The goal is for this to be possible to build, but not necessarily part of the initial implementation.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
The following features are out of scope for this BEP:
|
||||
|
||||
- Building out specific support for channels such as email, Slack, and other external channels.
|
||||
- Providing a fallback mechanisms when a notification cannot be delivered to a user. For example, if a user has not logged in for a long time, we will not attempt to send an email instead.
|
||||
|
||||
## Proposal
|
||||
|
||||
The notifications system is implemented through two net-new components, the `notifications` plugin, and the `signal` plugin.
|
||||
|
||||
The `notifications` plugin in its simplest form provides the following:
|
||||
|
||||
- A backend API for sending, reading, and interacting with notifications.
|
||||
- Persistent storage of notification state.
|
||||
- A frontend UI for viewing notifications.
|
||||
|
||||
The `signal` plugin provides the following:
|
||||
|
||||
- A backend API for pushing lightweight signals to online users.
|
||||
- A connection between the frontend and backend that can be used to push messages to the client.
|
||||
- A frontend API that lets plugins to subscribe to specific signals.
|
||||
|
||||
### Signals Plugin
|
||||
|
||||
In the backend the signal plugin implements a general purpose message bus for sending signals from backend plugins to connected users. It relies on the `EventBroker` from the [events plugin](https://github.com/backstage/backstage/blob/master/plugins/events-backend/README.md) for the actual message passing in the backend. In order to support scaled deployments, each signal backend instance has a separate subscription to the event broker so that each instance receives all events. It is then up to each backend instance to filter out events that are not relevant to it. For this reason, signals should be kept lightweight and not contain unnecessary data.
|
||||
|
||||
In the frontend the signal plugin has a persistent connection to the signal backend. This is initially implemented as a WebSocket connection, but could in the future also receive fallback mechanisms such as Server Sent Events or long polling. It is important that this connection is authenticated as we will be routing signals to specific users. The exact implementation of the authentication is not part of this proposal, but it should use whatever the outcome of the discussion in issue [#19581](https://github.com/backstage/backstage/issues/19581) is.
|
||||
|
||||
In order to route signals from the sender to the intended receiver the signal plugin uses the concept of signaling channels. They are just like the topics on the message bus, but we use separate terminology in order to avoid confusion. They also sit one layer beneath the even topic in the protocol stack, where the signal channel is communicated as part of the event payload. In the frontend, the signal plugin exposes an API to subscribe to a signal channel. Each time the user receives a signal on the specified channel, a listener is called with the signal payload.
|
||||
|
||||
### Notifications Plugin
|
||||
|
||||
The role of the notifications plugin is to manage the lifecycle of notifications. The backend plugin provides an API for other backends to send notifications, as well as an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services). It also provides a separate API for the frontend plugin to read notifications for an individual user and manage the read status of notifications.
|
||||
|
||||
The notification backend stores notification using the [database service](https://backstage.io/docs/backend-system/core-services/index#database). In particular it needs to store the following information for each notification:
|
||||
|
||||
- ID
|
||||
- Payload
|
||||
- Receivers
|
||||
- Read status by user
|
||||
|
||||
The receivers is **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal.
|
||||
|
||||
The notification backend does not provide any new permissions, since creating notifications can only be done by other backend plugins, while reading notifications can only be done by the authenticated user. It is possible that we want to add a permissions for reading notifications, in particular for admin and impersonation use cases, but that is not part of this proposal or the initial implementation.
|
||||
|
||||
The notification frontend plugin provides a UI for viewing notifications, which in the initial implementation can be as simple as needed. The only requirement is that a user is able to view recent notifications and distinguish between read and unread notifications. A notification as marked as read once it has been interacted with. The frontend plugin also subscribes to the notifications signal channel and alerts the user when a new notification is received.
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
The diagram below show an overview of the notifications system architecture and the interaction between the different components.
|
||||
|
||||

|
||||
|
||||
The components that are presented with dashed lines are not directly part of this proposal, but included to be considered as future extensions.
|
||||
|
||||
Let's walk through the process of sending of a notification to a user:
|
||||
|
||||
1. A backend plugin that wants to send a notification to a user uses the `NotificationService`, which in turn makes a POST request to the notification backend. The request contains a filter to select the target users, as well as the notification payload.
|
||||
|
||||
1b. As the notification backend handles the request it could optionally invoke a series of notification processors. These processors can be used to transform the notification payload, send the notification through other channels, and decide whether the regular notification flow should continue or not. This step is not in scope for this proposal.
|
||||
|
||||
2. The notification backend stores the received notification in its database. At this point the notification is available from the notification backend's read API.
|
||||
3. The notification backend published an event to the event bus on the `'signal'` topic. This event payload contains the signaling channel, in this case `'notifications'`, as well as the target user ID and the notification ID, but not the notification payload.
|
||||
4. Each instance of the signal backend plugin subscribes to the `'signal'` topic and receives the event.
|
||||
5. Each signal backend instance has a set of push channels set up to online users. The incoming event is filtered based on the target user ID and the signaling is pushed through all connections with a matching user ID.
|
||||
6. The signal frontend plugin receives the signal and forwards it to all subscribers of the target channel. In this case, the notifications frontend plugin, who is subscribed to the `'notifications'` channel.
|
||||
7. The notifications frontend plugin receives the signal with the notification ID. It then makes a request to the notification backend to fetch the notification payload and then displays the notification to the user.
|
||||
|
||||
7b. Rather than rendering the notification directly, the notifications frontend plugin leaves that to an extension installed by the frontend part of the backend plugin that sent the notification. This allows for a more customized notification experience which can also contain custom actions and data display. This step is not in scope for this proposal.
|
||||
|
||||
## Design Details
|
||||
|
||||
### Backend Services
|
||||
|
||||
The following backend service interfaces are added as part of this proposal.
|
||||
|
||||
#### `NotificationService`
|
||||
|
||||
```ts
|
||||
// TODO - We may want to add an additional wrapping here with interfaces for Notification and NotificationParameters
|
||||
|
||||
interface SendNotificationRequest {
|
||||
receivers: SignalReceivers;
|
||||
|
||||
/* TODO - please contribute :) */
|
||||
}
|
||||
|
||||
interface SendNotificationResponse {
|
||||
id: string;
|
||||
receivers: SignalReceivers;
|
||||
|
||||
/* TODO - please contribute :) */
|
||||
}
|
||||
|
||||
interface NotificationService {
|
||||
sendNotification(
|
||||
request: SendNotificationRequest,
|
||||
): Promise<SendNotificationResponse>;
|
||||
}
|
||||
```
|
||||
|
||||
#### `SignalService`
|
||||
|
||||
```ts
|
||||
type SignalReceivers =
|
||||
| {
|
||||
type: 'entity';
|
||||
entityRef: string; // typically a user or group entity
|
||||
}
|
||||
| {
|
||||
type: 'broadcast'; // all users
|
||||
};
|
||||
|
||||
interface Signal {
|
||||
channel: string;
|
||||
receivers: SignalReceivers;
|
||||
payload: JsonObject;
|
||||
}
|
||||
|
||||
interface SignalService {
|
||||
signal(signal: Signal): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
### Frontend API
|
||||
|
||||
The following frontend API is added as part of this proposal.
|
||||
|
||||
#### `SignalApi`
|
||||
|
||||
> TODO - we likely need a slightly different approach here, since APIs are lazy loaded.
|
||||
|
||||
```ts
|
||||
interface SignalSubscriber {
|
||||
unsubscribe(): void;
|
||||
}
|
||||
|
||||
interface SignalApi {
|
||||
subscribe(
|
||||
channel: string,
|
||||
listener: (payload: JsonObject) => void,
|
||||
): SignalSubscriber;
|
||||
}
|
||||
```
|
||||
|
||||
> TODO: Add payload formats and API details
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
- A notification can be sent to any entity
|
||||
- If the entity is an user, the notification is sent to that user
|
||||
- If the entity is a group, the notification is sent to all users that are members of that group
|
||||
- In other cases, the notification is sent to to the user or group in the `spec.owner` field
|
||||
- Notification frontend shows users their own notifications in its own page and the number of unread notifications
|
||||
in the main menu item
|
||||
- Notifications can be set to `read` by the user and they are filtered out of the main view
|
||||
- Notifications can be saved for later use by the user
|
||||
- Each notification must have title, description and link
|
||||
- Each notification can also have icon or image as an URL
|
||||
- Notification frontend utilizes [Web Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification)
|
||||
to notify user for new notifications
|
||||
|
||||
-->
|
||||
|
||||
## Release Plan
|
||||
|
||||
The notification and signal plugins are released as two new plugins in the Backstage ecosystem. They will both start out in an experimental state.
|
||||
|
||||
For the notification plugin to reach a stable release we much reach the following:
|
||||
|
||||
- A stable notifications payload format.
|
||||
- A stable notifications receiver filter format.
|
||||
- The event broker must have at least one implementation that supports scaled deployments.
|
||||
|
||||
For the signal plugin to reach a stable release we much reach the following:
|
||||
|
||||
- A stable signal receiver filter format.
|
||||
- A stable signal channel API in the frontend.
|
||||
|
||||
If any changes are required to the frontend framework to facilitate the implementation of notifications or signals, these will be released as experimental alpha features. They will stay in alpha until they are deemed stable enough, which must happen before a stable release of the notifications system.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Since the signal plugin relies on the event broker for communication, it is a dependency for the notifications system as a whole. The event broker does not currently implement any transport for scaled deployments, which is a requirement for scaled deployments of the notification system.
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Signal Plugin Separation
|
||||
|
||||
One primary consideration for the notifications system was whether the notification plugin should set up its own frontend push connection rather than relying on the signal plugin. The signal plugin separation is done for three primary reasons:
|
||||
|
||||
1. The use-case of sending signals from backend plugins to frontend plugins is not limited to only notifications, since not all signals should necessarily be displayed directly to the user. For example, the catalog backend may want to send a signal to the frontend when an entity is updated so that users that are currently viewing the entity in the frontend can trigger an update of the view.
|
||||
2. We want to limit the number of WebSocket connections that the frontend needs to maintain. By using a separated signal abstraction it is easier to extend the implementation to support other messaging patterns in the future. For example, we may want to move the Scaffolder logs to be sent via the signal plugin instead. That is much more straightforward with a separate signal plugin compared to adding it to the notifications plugin.
|
||||
3. The technical implementation of sending signals is sufficiently complex that it makes sense to separate out to its own solution in order to reduce the complexity of the notifications plugin. In particular when it comes to handling scaled deployments.
|
||||
|
||||
### User-to-User Notifications
|
||||
|
||||
The notification backend API for sending notifications is only available to other backend plugins, and is not accessible to end users in the frontend. If this were to be added it would likely be a separate backend module that you can install alongside the notification backend. That is unless the permission framework can be extended to support default policy handlers so that we can reject the permission to send user notifications by default.
|
||||
|
||||
There are a few reasons we don't want to allow user-to-user notifications out of the box:
|
||||
|
||||
- To limit the possibility of spam. Even if well-intended, a notification overload can quickly lead to a bad user experience and users disabling and ignoring notifications.
|
||||
- From a security perspective it's beneficial to avoid user sent notifications since they could be used to trick users into clicking on malicious links, or other similar attacks.
|
||||
- Our assumption is that this is a feature that most adopters will not want to use, and so by having it be disabled by default we can avoid additional configuration steps.
|
||||
@@ -0,0 +1,537 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="671px" height="311px" viewBox="-0.5 -0.5 671 311" content="<mxfile scale="1" border="20"><diagram id="2fh7CcgDxUdRYRy3FD-Z" name="Page-1">7Vxbk6I4FP41Vu0+tEVAUB9bu+192N3pWqdqZx4jREk1Agto6/76TSDckqhIA97W6RrJIdy+79xyEulp0/XuLYC+/YdnIaenKtaup730VHU40Mn/VLBPBCPDSASrAFuJCOSCOf4XMaHCpBtsobDUMfI8J8J+WWh6rovMqCSDQeB9lrstPad8VR+ukCCYm9ARpX9jK7ITqTZWcvlvCK9sdmXNYDsW0PxYBd7GZZfrqdos/iS71zA9Fesf2tDyPgsi7bWnTQPPi5Kt9W6KHIpsilpy3OzA3uy2A+RGVQ5IeQqjffroyCJIsKbrueRrYkdrh7QA2bRgaCOLNZaeGzHuCHHaJIxgED1T+PNjY9kMO/QEtA9yLa4HkRT373D0g273VZ01fxZ2veyKjT1riI/NkAi9TWCyB1OZHsFghVivwTCR0WcuHMewekPeGkXBnnQIkAMjvC1rB2RKtsr6ZYe+e5jciaowe3gCKgN6n+q5Uj5HclfssJwwslG4j1wU0yin1FDPpDRHfFgdcQJ0sE+O0tPmz/SEtJEfFrdKx72jAJMnQgETflGPFo5nfny3sVtSplhByebUc7wgxkFb6vRffLLA+0CFPUb8+YImpQ6gYU0ijwj3hQ4+VZDwiKKlHirVM97++f7G0f5kI7mDusrIkNpCZ8Oe+E8vwktsEgw8l+yZEIdJOBNUNvahsaOhZH/aOEJzH8YEfJKIU9bgQzRTvSrIk089+rcoiNDuKLOZrY84TAes/ZlHkhRnxS5EkYFyWBtKDuEI4Ok5zrf+oun39aPG35q9lqNLO8aricY7atp2K7M1qu2rq7vqW/OuEoLUSxGknfJfs4Cge+cOLAtunTgwAfE5XrnQuctYoVeIFEpLQKdG1arvOZXtl3xR0dMUHVKLvkYXfc3gUr4mdTYtE1I3bz9OZHf8AL1pgmpl2pldpk7yRKYNxkf7fz3THvyvPVW0x7hJ7eEjRePaM66rPWcMGzLtAUXdKajSAe259oRVombapYKIfjh9usNUlbcKWaLaVv5U12JAHYtRzrOY8xW9kv1UsgZDtIaLDd8MwRrenc0K04Hbj7scUDxpfEGvy+LT6Djc1+aAStWmNsDvdOAMzh7PXZdzqeMfKzkkSbUeNB6fD8378BoBOKaTGxXmfcQzqVzGmJ35xAzSuZmpKr/MwcS03H3UbFoKhjWDbHlQA44q0aFBjXLCDi6ZcgJJkfRihQvQTBX7MVi60vLFqYlCvnzR9EQhqD0AfUQdus4ixikdEsrdTeuQOFvzukXxHUwoB8G1JJ4N5JpcXiFJNEdt5ZliieGOcAXD0+OnQVvIisPVO0JW1S6HbJqlFpDt9/sCuORJojKCZURYFCrCykTQwSsSEl5Mgg9d1jShuGATOs9sxxpbFr2MlLIyqU1ocYWJxbbGodndPgjW2ZDuAlhrqoC1v1k4OLRpdpDEvqvEnV+T0gAPwlI2CQ+ymKg2wYO4amEReNAyYfhADGSI84tcu2BAkpVoM/b3OAxw5RhVwoDeFgNi9hKiYEuzbsXfUI/0MCzwk7uayMKwLRbGAgvv3+bfHwf8J5X3QpI4YLSE/uDcRRhN/pyi89JE+uuJUhGSZSTtV9a5gtSIo+9AYb1GWSF9pGJZYUdUP5lVn+/DCK0F2u9mSosbSXS6FFSs56A1xKTLLHSg+UG+IwTXYU+dUo2LzGsdZbTh5nhiqs7zNuLmxFD/F/E4kgLb/eLPhxmZZbQWZoYC/j3VcCjSoQ/dEgXGPxv6Y8KJmcD7TF3vavGLDhKryb9/jYFRKFZPYQwW7QtUfxfvSM9Dtlb0+z3wTBSG5JzsytQq44sn+8VA6DjYDw8RVjUmXlVJSwhCHZZhB2Ki9/b6SHmeMNYBIvhaSwaY+t4C+ECAvrLCw9BPfsO8xDsK2UmlXy5V05Qpt2UsDL0p5RYKtkMR4LYijC4WESWr428cYL5I2yW+Yk4LFncHsPBLTImLaA1hsSQoGRzeNsD8XFmX8Ir1PsmrDG4bXsDPLIw7xFdM8Y17w5dPILqEV8zgh/fnf/mpsU4RFvNjyWLCGweYn+eVVZrbAjgd6xxbrRDa0Keb5t7BtD6gnUZ6kQwcfl9kguyVOt82ETkNYvJkjPoy6I8NNf8bXP+gkUtKdJEy2TIIvQnKxIKayNnN2wTgXrXTYVZiiEnf1IauG78cawodZxGXLW9ojC4AL6Gn8pS8tHoMmuGCNPPXZiVV/vzNZNrrfw==</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<path d="M 230 120 L 230 80" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||
<path d="M 290 120 L 290 110 Q 290 100 300 100 L 310 100 Q 320 100 320 94.06 L 320 88.12" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 320 81.12 L 322.33 88.12 L 317.67 88.12 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="200" y="120" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 140px; margin-left: 201px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Notification Backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="260" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Notification Backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 200 260 L 148.12 260" fill="none" stroke="#666666" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||
<path d="M 141.12 260 L 148.12 257.67 L 148.12 262.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 260 240 L 260 168.12" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 260 161.12 L 262.33 168.12 L 257.67 168.12 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="200" y="240" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 260px; margin-left: 201px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Notification Frontend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="260" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Notification Frontend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="430" y="120" width="100" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 140px; margin-left: 431px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Signal Backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="480" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Signal Backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 480 231.88 L 480 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 480 238.88 L 477.67 231.88 L 482.33 231.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 480 240 L 480 210 Q 480 200 490 200 L 560 200 Q 570 200 570 190 L 570 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 480 240 L 480 210 Q 480 200 490 200 L 620 200 Q 630 200 630 190 L 630 160" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 430 260 L 328.12 260" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 321.12 260 L 328.12 257.67 L 328.12 262.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="430" y="240" width="100" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 260px; margin-left: 431px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Signal Frontend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="480" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Signal Frontend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 140 140 L 191.88 140" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 198.88 140 L 191.88 142.33 L 191.88 137.67 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="20" y="120" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 140px; margin-left: 21px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Plugin X Backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="80" y="144" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Plugin X Backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="20" y="240" width="120" height="40" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 260px; margin-left: 21px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Plugin X Frontend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="80" y="264" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Plugin X Frontend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 320 140 L 390 140 Q 400 140 400 130 L 400 70 Q 400 60 410 60 L 431.88 60" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 438.88 60 L 431.88 62.33 L 431.88 57.67 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 480 80 L 480 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 480 118.88 L 477.67 111.88 L 482.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 480 80 L 480 90 Q 480 100 490 100 L 560 100 Q 570 100 570 105.94 L 570 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 570 118.88 L 567.67 111.88 L 572.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 480 80 L 480 90 Q 480 100 490 100 L 620 100 Q 630 100 630 105.94 L 630 111.88" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 630 118.88 L 627.67 111.88 L 632.33 111.88 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="440" y="40" width="80" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 60px; margin-left: 441px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Event Broker
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="480" y="64" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Event Broker
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="550" y="120" width="40" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<rect x="610" y="120" width="40" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/>
|
||||
<rect x="530" y="120" width="20" height="40" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 140px; margin-left: 531px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="540" y="144" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="590" y="120" width="20" height="40" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 140px; margin-left: 591px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="600" y="144" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="320" y="120" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 130px; margin-left: 321px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
publish event
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="360" y="133" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
publish event
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="520" y="80" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 90px; margin-left: 521px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
broadcast
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="560" y="93" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
broadcast
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="500" y="180" width="50" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 190px; margin-left: 501px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
???
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="525" y="193" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
???
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="480" y="210" width="70" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 220px; margin-left: 481px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
server push
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="515" y="223" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
server push
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="140" y="120" width="60" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 130px; margin-left: 141px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
POST
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="170" y="133" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
POST
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 190 60 L 158.12 60" fill="none" stroke="#666666" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||
<path d="M 151.12 60 L 158.12 57.67 L 158.12 62.33 Z" fill="#666666" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="30" y="40" width="120" height="40" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 31px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
External System
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="90" y="64" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
External System
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="30" y="20" width="120" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 30px; margin-left: 31px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
email/slack/teams, etc.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="90" y="33" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
email/slack/teams, etc.
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="140" y="240" width="60" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 250px; margin-left: 141px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Render
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="170" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
Render
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="230" cy="60" rx="40" ry="20" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 60px; margin-left: 191px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
<span style="color: rgb(51, 51, 51); font-size: 12px;">
|
||||
Processor
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="230" y="63" fill="#333333" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
Processor
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="260" y="190" width="30" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 200px; margin-left: 261px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
GET
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="275" y="203" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
GET
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="160" cy="160" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 160px; margin-left: 151px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
1
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="160" y="163" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
1
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="340" cy="160" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 160px; margin-left: 331px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
3
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="340" y="163" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
3
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="210" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 201px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
1b
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="210" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
1b
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="460" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 451px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
4
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="460" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
4
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="500" cy="180" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 180px; margin-left: 491px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
5
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="500" y="183" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
5
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="410" cy="280" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 280px; margin-left: 401px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
6
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="410" y="283" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
6
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="180" cy="280" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 280px; margin-left: 171px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
7b
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="180" y="283" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
7b
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<ellipse cx="240" cy="220" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 220px; margin-left: 231px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
7
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="240" y="223" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
7
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 300 34.96 C 300 32.22 308.95 30 320 30 C 325.3 30 330.39 30.52 334.14 31.45 C 337.89 32.38 340 33.65 340 34.96 L 340 75.04 C 340 76.35 337.89 77.62 334.14 78.55 C 330.39 79.48 325.3 80 320 80 C 314.7 80 309.61 79.48 305.86 78.55 C 302.11 77.62 300 76.35 300 75.04 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 340 34.96 C 340 36.28 337.89 37.54 334.14 38.47 C 330.39 39.4 325.3 39.93 320 39.93 C 314.7 39.93 309.61 39.4 305.86 38.47 C 302.11 37.54 300 36.28 300 34.96" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<ellipse cx="275" cy="100" rx="10" ry="10" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 100px; margin-left: 266px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
2
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="275" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
2
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="320" y="240" width="110" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 250px; margin-left: 321px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Channel Callback
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="375" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">
|
||||
Channel Callback
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
|
||||
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||
Text is not SVG - cannot display
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: BEP Title
|
||||
status: provisional
|
||||
authors:
|
||||
- '@ghost'
|
||||
owners:
|
||||
project-areas:
|
||||
- aaa
|
||||
- bbb
|
||||
creation-date: yyyy-mm-dd
|
||||
---
|
||||
|
||||
<!--
|
||||
**Note:** When your BEP is complete, all these pre-existing comments should be removed
|
||||
|
||||
When editing BEPs, aim for tightly-scoped, single-topic PRs to keep discussions focused. If you disagree with what is already in a document, open a new PR with suggested changes.
|
||||
-->
|
||||
|
||||
# BEP: <!-- Your short, descriptive title -->
|
||||
|
||||
<!-- Before merging the initial BEP PR, create a feature issue and update the below link. You can wait with this step until the BEP is ready to be merged. -->
|
||||
|
||||
[**Discussion Issue**](https://github.com/backstage/backstage/issues/NNNNN)
|
||||
|
||||
- [Summary](#summary)
|
||||
- [Motivation](#motivation)
|
||||
- [Goals](#goals)
|
||||
- [Non-Goals](#non-goals)
|
||||
- [Proposal](#proposal)
|
||||
- [Design Details](#design-details)
|
||||
- [Release Plan](#release-plan)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Alternatives](#alternatives)
|
||||
|
||||
## Summary
|
||||
|
||||
<!--
|
||||
The summary of the BEP is a few paragraphs long and give a high-level overview of the features to be implemented. It should be possible to read *only* the summary and understand what the BEP is proposing to accomplish and what impact it has for users.
|
||||
-->
|
||||
|
||||
## Motivation
|
||||
|
||||
<!--
|
||||
This section is for explicitly listing the motivation, goals, and non-goals of
|
||||
this BEP. Describe why the change is important and the benefits to users.
|
||||
-->
|
||||
|
||||
### Goals
|
||||
|
||||
<!--
|
||||
List the specific goals of the BEP. What is it trying to achieve? How will we
|
||||
know that this has succeeded?
|
||||
-->
|
||||
|
||||
### Non-Goals
|
||||
|
||||
<!--
|
||||
What is out of scope for this BEP? Listing non-goals helps to focus discussion
|
||||
and make progress.
|
||||
-->
|
||||
|
||||
## Proposal
|
||||
|
||||
<!--
|
||||
This is where we get down to the specifics of what the proposal actually is.
|
||||
This should have enough detail that reviewers can understand exactly what
|
||||
you're proposing, but should not include things like API designs or
|
||||
implementation.
|
||||
-->
|
||||
|
||||
## Design Details
|
||||
|
||||
<!--
|
||||
This section should contain enough information that the specifics of your
|
||||
change are understandable. This may include API specs or even code snippets.
|
||||
If there's any ambiguity about HOW your proposal will be implemented, this is the place to discuss them.
|
||||
-->
|
||||
|
||||
## Release Plan
|
||||
|
||||
<!--
|
||||
This section should describe the rollout process for any new features. It must take our version policies into account and plan for a phased rollout if this change affects any existing stable APIs.
|
||||
|
||||
If there is any particular feedback to be gathered during the rollout, this should be described here as well.
|
||||
-->
|
||||
|
||||
## Dependencies
|
||||
|
||||
<!--
|
||||
List any dependencies that this work has on other BEPs or features.
|
||||
-->
|
||||
|
||||
## Alternatives
|
||||
|
||||
<!--
|
||||
What other approaches did you consider, and why did you rule them out? These do
|
||||
not need to be as detailed as the proposal, but should include enough
|
||||
information to express the idea and why it was not acceptable.
|
||||
-->
|
||||
@@ -0,0 +1,86 @@
|
||||
# Backstage Enhancement Proposals (BEPs)
|
||||
|
||||
A Backstage Enhancement Proposal (BEP) is a way to propose, communicate and coordinate on new efforts for the Backstage project.
|
||||
|
||||
## Quick start for the BEP process
|
||||
|
||||
1. Discuss the idea with the community and maintainers. Either here on GitHub, Discord, or during community sessions or SIG meetings.
|
||||
Make sure that others think the work is worth taking up and will help review the BEP and any code changes required.
|
||||
1. Make a copy of the [BEP template](./NNNN-template/) directory as `beps/NNNN-short-descriptive-title`, where `NNNN` is the next available number padded with leading zeroes.
|
||||
1. Fill out as much of the YAML metadata as you can.
|
||||
1. Fill out the template as best you can.
|
||||
1. If you want the BEP to be owned by a particular project area, add an entry for the BEP folder to [CODEOWNERS](../.github/CODEOWNERS).
|
||||
1. Create a PR for the BEP. Title it "BEP: <title>". Aim to get the high level goals clarified and avoid getting hung up on specific details. The PR can be merged early and iterated on.
|
||||
1. Once the BEP is ready to be merged, create a [feature issue](https://github.com/backstage/backstage/issues/new?template=feature.yaml) titled "BEP: <title>". Use the summary of the BEP as description and link to the BEP PR in the context section. Once the PR is merged, the issue should be updated to link to the BEP folder instead. This issue will serve as a general discussion issue for the BEP.
|
||||
1. Once the initial BEP is merged you should keep iterating on it until it is ready to leave that `provisional` state. Leaving the `provisional` state is a decision made by the project area maintainers.
|
||||
|
||||
Just because a BEP is merged does not mean it is complete or approved for implementation. Any BEP marked as `provisional` is a working document and subject to change.
|
||||
|
||||
The authors of the BEP are also responsible for driving the BEP forward all the way to implementation. The approval of a BEP is not a commitment to implement it.
|
||||
|
||||
## FAQs
|
||||
|
||||
### Do I have to use the BEP process?
|
||||
|
||||
No, but it is recommended for larger changes and contributions that affect the Backstage framework or core features where you want to make design decisions upfront and iterate on them across several PRs.
|
||||
|
||||
### What is the difference between a BEP and an RFC issue?
|
||||
|
||||
An RFC issue is a good way to receive feedback on an idea. The BEP process may involve getting feedback on an idea, but it takes things further by making it easier to iterate on the design of a new feature, getting it approved by the owning project area maintainers, and tracking its implementation.
|
||||
|
||||
While anyone can open an RFC issue, the features added by a BEP need to be approved by the owners before it can be merged. The BEP will also contain the latest agreed upon design, whereas an RFC issue is more of a discussion forum.
|
||||
|
||||
Often a BEP can start out as an RFC issue, which may then be converted into a BEP once the idea has received an owner and been approved.
|
||||
|
||||
### Should I use the BEP process for new or existing Backstage plugins?
|
||||
|
||||
No, except for plugins that implement core features of Backstage. The BEP process is only intended for changes to the Backstage framework and core features.
|
||||
|
||||
### Can I update an existing BEP?
|
||||
|
||||
Yes! As long as the BEP is still in the `provisional` state you should keep iterating on it. Please keep each PR focused on a single topic and avoid long-running and overly broad PRs.
|
||||
|
||||
### Can I update a BEP that was submitted by someone else?
|
||||
|
||||
Yes! BEPs are living documents and anyone can suggest changes to them. We encourage to challenge the design decisions in a BEP and suggest alternatives. You can also help fill out details in a BEP that has not yet been fully fleshed out.
|
||||
|
||||
### What's the difference between a BEP and an [ADR](https://backstage.io/docs/architecture-decisions/)?
|
||||
|
||||
Architecture Decision Records (ADRs) are used to document decisions made for development within the Backstage project. They are not intended to be used for proposing new features or changes to Backstage.
|
||||
|
||||
### My FAQ isn't answered here!
|
||||
|
||||
The BEP process is still evolving!
|
||||
|
||||
If something is missing or not answered here feel free to reach out on our community [Discord](https://discord.gg/backstage-687207715902193673).
|
||||
If you want to propose a change to the BEP process you can also open a PR directly with your proposal.
|
||||
|
||||
### BEP Metadata
|
||||
|
||||
At the start of each BEP is a YAML document that contains metadata about the BEP. These are the fields that should currently be provided:
|
||||
|
||||
| Field | Description |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **title** | The title of the BEP in plain language. The title will also be used in the BEP filename. See the template for instructions and details. |
|
||||
| **status** | The current state of the BEP, must be one of the values listed in the [BEP Status](#bep-status) section. |
|
||||
| **authors** | A list of GitHub IDs for the authors of the BEP. Typically only the original authors are included, but additional authors can be added if significant contributions are made. |
|
||||
| **owners** | A list of GitHub IDs for the owners of the BEP. The owners are responsible for the implementation of the BEP, and are required for the BEP to move to the `implementable` status. |
|
||||
| **project-areas** | The Project Areas closely associated with this BEP that need to approve it. For a list of existing project areas, see [OWNERS.md](../OWNERS.md). If the BEP is not related to any existing project area, use `core-maintainers` instead. |
|
||||
| **creation-date** | The `yyyy-mm-dd` date that the BEP was first submitted in a PR. |
|
||||
|
||||
## BEP Status
|
||||
|
||||
The BEP Status is critical to clearly communicate the status of each BEP. Each BEP must have its status field set to one of the following values:
|
||||
|
||||
- `provisional`: The BEP has been proposed and is actively being defined. The BEP as been approved by the owning project area maintainers as work to be done.
|
||||
- `implementable`: The approvers have approved this BEP for implementation.
|
||||
- `implemented`: The BEP has been implemented and is no longer actively changed.
|
||||
- `deferred`: The BEP is proposed but not actively being worked on.
|
||||
- `rejected`: The approvers and authors have decided that this BEP is not moving forward.
|
||||
The BEP is kept around as a historical document.
|
||||
- `withdrawn`: The authors have withdrawn the BEP.
|
||||
- `replaced`: The BEP has been replaced by a new BEP.
|
||||
|
||||
### Prior Art
|
||||
|
||||
The BEP process is heavily inspired by the [Kubernetes Enhancement Proposal (KEP) process](https://github.com/kubernetes/enhancements/blob/master/keps/README.md).
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 13.2.25
|
||||
digest: sha256:59939b2a3ac354f0818ad48d05aba3ab38c3c9d44dcdbd7871c8f352f07d86e5
|
||||
generated: "2023-12-20T22:07:31.631181349Z"
|
||||
version: 13.2.27
|
||||
digest: sha256:c2272865ffe4c805153440d8fc6af84945d4ce566b14d0fa8698d75382ada06c
|
||||
generated: "2023-12-31T14:23:23.75461574Z"
|
||||
|
||||
@@ -18,7 +18,7 @@ sources:
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
condition: postgresql.enabled
|
||||
version: 13.2.25
|
||||
version: 13.2.27
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="897px" height="646px" viewBox="-0.5 -0.5 897 646" content="<mxfile scale="1.5" border="20"><diagram id="gKBvn7eBFHudv9VMIRD-" name="Page-1">7V1tb6M4EP41kXZPahVwIPCxabe3J3V11fWku/3oECdBS3HOkG2zv/5ssHkzJIQQ0xCyUjcM2JiZeWbG4zEZgfvX998J3Ky/4QXyRvp48T4CDyNdN0xA/zLCLibYUzMmrIi7iElaSnhxfyFOHHPq1l2gIHdhiLEXups80cG+j5wwR4OE4Lf8ZUvs5e+6gSskEV4c6MnUf9xFuI6pYDJO6V+Ru1qLO1v8xBw6P1YEb31+u5EOltEnPv0KRVf8+mANF/gtQwJfRuCeYBzG317f75HHOCu4Frd7rDibDJsgP6zTwOAtfkJvi8SQo4GFO8GL6HEQazAegdnb2g3RywY67OwbFT6lrcNXjx5p9OvS9bx77GEStQVLg/2j9CAk+AfKnDGjD2uB/TBDjz+UzgeGSIjeK59OS3hGNRHhVxSSHb1ENNCNuAnXwhshv7dUptqY09YZeYrrIFejVdJ1ykv6hbOzgrV6r1mrdcjaid1n1t4I49CJ1o57zVrQIWsnVq9Zq5ld8nbab95Ou+TtWGIlWtBoiR/62Ed53qF3N/yXsflWN/jhd8519v3hPXuwEwc+HVbcyhCH30WH7CBtFh2l7RZ3LOCjh3MPOz/+Xrt+TH50PTGiIIQk5FHmJD6bOTpe1jFDGBf2S5QyDW+Jw6/iKknHskL8KlAheII8GLo/892fJEStsRCPkeFFy0JXJQvZNtWVxXQA1AEhThUJUY7uZ3TuR/lAiQ9o4+HdKxu6Pr77WI6ohKWSb9rjiKwuHZHE8kdCnzXm+d1m0ydGFwJVzZD5bJ2JzSWqfay9OqfpyZuaoiHKi5wx3HWgd+e5K9rTw6u7WHjRYDFxf1HxwUT69IB3Yzf0fk2t3gEjN5GNnEhrFOzlCVaPN33GbmSzxCV4uQzoTTPKk17DNRUUNLWogfGj8EZ7+ilMerViP/HzS/1Eypw8cT39tveqMybhGq+wD70vKfWSw1tnS35GiGhm5Rq6ZqNEbRW5ZsOQDNhddAEO14iwQRG4XLpOqRo8wTny8gKH3Ho49IFp+z1mhaDA/QXnUX9MehumrtGTGLOR8bBvNsgz2bzxKMFDls+x5lY7jfGtZml8JtwU+omnz+f39AIcZcvQAIlg/8zyCCReRlz8cZBoqoKiHLPRJnDjsh6msxA56wV2gpF+HzgUk9hbUIBN6WWPv10cOsG4nKm8J+ourCnIgepGawerZt512meAqi7b1E93W2pPfcbr0PVXn+nZvxDlXYDot2eC33eSCC84BTfJxyeWynmPsddMDgm42qbQlE0hMBSZwonZWIqX4d06laIqhyZufjjvc98j65eYtk7SPmAwf+0AZ1oCHKDK/E0G83c+KU5UmT95nbXC/M16ZP6KwZ9S82fujxvKJ8m5meb1rOoBUSuYwYapChvi5hlswI+2KHFqYVIBB4nSZ4AwKcEBaAMH0wEHtXGgyzgwLFU40GUcbKl29AgIyXJcJ0Bosn5xrUAAJQ6hIk/XPhCABAQHhtDDqz5hoQ4UjDNBYdpkAeFaoVCykGyqKj8D8jpAgCBx+uQVimXbSoGwv7xvAEIWCCULYqauCgjyOkq6CNYbKNg1oGCeCwr6AIXaUChJpZuqMoJATqVnFoH7AwapeF8lGkxrQENtNJRkVo2Kkpv20SBnVjd9W0OXlpFUTpuBvP3q2duuXF92vMEabthXigNvNyMswR0e5nUqGHbksUqVZxy4oYtZFYqHlqwPUZzyVDidFKmIchYSP311NcsCBuvkbm1IRy9ujtM0WTqgRDpGG9KpsaVzEEtuwn1AKmYLUjFkF93AnVx9ZfjHqfs7dXdMoQDtiDrxYn23VVDPpnXiRdfQXp24UbanNK1dTFJ59zyTcaFli0ZF6UxStjixRMZ5l+u8faVpICS78/iWHjwj4tIxMzGeWIVAj+TOLiaANizZ5Fiqll+NGtvrkwhi57nUGRBwOHyYx27jaZ4Qkle8/LkNaTdIiIDz+9aYahPd4n+tffyvirUPyeXEKLxYzaCJDROZiEI/UxRud754NeA1xavdJV6PifivGa9SMlUhXJMJ+oDXD4BXMaXL4VXVhndx8wGvh7ZuF96MpRavnS8EDnhN8VpSjqgOr3I54oDXErx2C9cm+bQBrmeCqy7D1VZVLCZuPsD1wGqq1mk4vH8vUld4vRyInVpcUJ4Ult49KKWX20sLm3JV5wDUMqB2OW+1O980M/jVFPQllafK0kxm2RsoBriWpIW7xKspl0VWS+m6l/8TX3dg/b+NvYfTMl9neowDwQb6OfmY/23ZW+tnuW8r9v/XZEndY08WvWZ/IfqhQ4i7iq8V5Dkp7XyOCcXnjRNj4C4aGvl0c5Olfy4dRINxp/tZg8rRFnSUCjrM618etHybcxb5nFRbw8r0PV/b0IbageIiEZCNQRKKt17CK9vsJ7xi3KDEBxjCOQyQXLbVX+aXmeKzcd+uEeAyT7epfNQ6ZQfHLlLq43reSJS9nMIBa4gZwqwuyGISlSCyKyqTidaGTI6JEK5ZJvVg0opIalQHXrdIFAjBrmGrzmatOzHONX7q4Uq0rmIO3YFxHmqv6slEoXEeymsOiESFca4RtJw7lJbeVaHSWIuc0qCFdsV7JtUba3soDKgnE3XG2tYHkewXiQIhaONjpv3XnYTWNf1Whse50tDaWPajD7NvL5Tyhx+E0HeuKhuoj6clzG8rHzhiv6ojfn82Xh9Pf+IXfPkf</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<rect x="717" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="702" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="499.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="484.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="289.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="274.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<path d="M 297 279 L 265.37 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 260.57 235.29 L 267.3 239.45 L 263.45 242.65 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 334.5 279 L 334.5 243.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 235.68 L 337 243.18 L 332 243.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 372 279 L 403.63 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 408.43 235.29 L 405.55 242.65 L 401.7 239.45 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="259.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 174px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Backend Deployment A
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="223" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Backend Deployme...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="484.5" y="564" width="120" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 396px; margin-left: 324px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Frontend App
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="363" y="400" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Frontend App
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 544.5 564 L 544.5 528.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 544.5 520.68 L 547 528.18 L 542 528.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 507 459 Q 507 399 420.75 399 Q 334.5 399 334.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 340.68 L 337 348.18 L 332 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 286px; margin-left: 284px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
All other traffic
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="284" y="290" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
All other traffic
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 582 459 Q 582 399 668.25 399 Q 754.5 399 754.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 754.5 340.68 L 757 348.18 L 752 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 286px; margin-left: 468px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
/api/{techdocs,scaffolder}/*
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="468" y="290" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
/api/{techdocs,scaffolder}/*
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="469.5" y="459" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 326px; margin-left: 314px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
(Authenticating) Reverse Proxy
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="363" y="330" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
(Authenticating)...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 717 279 L 711.01 243.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 709.78 235.65 L 713.47 242.64 L 708.54 243.46 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 792 279 L 823.63 241.05" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 828.43 235.29 L 825.55 242.65 L 821.7 239.45 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="679.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 454px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Backend Deployment C
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="503" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Backend Deployme...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 507 279 L 494.9 242.71" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 492.53 235.59 L 497.27 241.92 L 492.53 243.5 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 582 279 L 594.1 242.71" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 596.47 235.59 L 596.47 243.5 L 591.73 241.92 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="469.5" y="279" width="150" height="60" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 206px; margin-left: 314px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Backend Deployment B
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="363" y="210" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Backend Deployme...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 259.5 189 Q 259.5 189 259.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 259.5 153.18 L 262 160.68 L 257 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="229.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 154px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
app
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="173" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
app
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 334.5 189 Q 334.5 189 334.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 153.18 L 337 160.68 L 332 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="304.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 204px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
auth
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="223" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
auth
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 492 189 Q 492 189 492 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 492 153.18 L 494.5 160.68 L 489.5 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="454.5" y="189" width="75" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 141px; margin-left: 304px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
catalog
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="328" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
catalog
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 597 189 Q 597 189 597 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 597 153.18 L 599.5 160.68 L 594.5 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="559.5" y="189" width="75" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 141px; margin-left: 374px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
search
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="398" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
search
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 709.5 189 Q 709.5 189 709.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 709.5 153.18 L 712 160.68 L 707 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="664.5" y="189" width="90" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 141px; margin-left: 444px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
techdocs
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="473" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
techdocs
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 829.5 189 Q 829.5 189 829.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 829.5 153.18 L 832 160.68 L 827 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="784.5" y="189" width="90" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 141px; margin-left: 524px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
scaffolder
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="553" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
scaffolder
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 409.5 189 Q 409.5 189 409.5 160.68" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 409.5 153.18 L 412 160.68 L 407 160.68 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="379.5" y="189" width="60" height="45" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 141px; margin-left: 254px;">
|
||||
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
proxy
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="273" y="145" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
proxy
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 229.5 174 L 218.25 174 Q 207 174 207 189 L 207 200.25 Q 207 211.5 195.75 211.5 L 190.13 211.5 Q 184.5 211.5 195.75 211.5 L 201.38 211.5 Q 207 211.5 207 226.5 L 207 237.75 Q 207 249 218.25 249 L 229.5 249" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 32px; height: 1px; padding-top: 141px; margin-left: 89px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Plugins
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="121" y="145" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
|
||||
Plugi...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 229.5 264 L 218.25 264 Q 207 264 207 279 L 207 294 Q 207 309 195.75 309 L 190.13 309 Q 184.5 309 195.75 309 L 201.38 309 Q 207 309 207 324 L 207 339 Q 207 354 218.25 354 L 229.5 354" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
|
||||
<path d="M 544.5 459 Q 544.5 459 544.5 348.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 544.5 340.68 L 547 348.18 L 542 348.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 247px; margin-left: 362px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
|
||||
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
/api/{catalog,search}/*
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="362" y="250" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||
/api/{catalog,search}/*
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 334.5 106.5 Q 334.5 106.5 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 319.5 113.36 C 319.5 109.57 326.22 106.5 334.5 106.5 C 338.48 106.5 342.29 107.22 345.11 108.51 C 347.92 109.79 349.5 111.54 349.5 113.36 L 349.5 144.64 C 349.5 148.43 342.78 151.5 334.5 151.5 C 326.22 151.5 319.5 148.43 319.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 349.5 113.36 C 349.5 117.14 342.78 120.21 334.5 120.21 C 326.22 120.21 319.5 117.14 319.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 409.5 106.5 Q 409.5 87.78 372 87.78 Q 334.5 87.78 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 394.5 113.36 C 394.5 109.57 401.22 106.5 409.5 106.5 C 413.48 106.5 417.29 107.22 420.11 108.51 C 422.92 109.79 424.5 111.54 424.5 113.36 L 424.5 144.64 C 424.5 148.43 417.78 151.5 409.5 151.5 C 401.22 151.5 394.5 148.43 394.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 424.5 113.36 C 424.5 117.14 417.78 120.21 409.5 120.21 C 401.22 120.21 394.5 117.14 394.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 492 106.5 Q 492 87.78 518.25 87.78 Q 544.5 87.78 544.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 544.5 70.68 L 547 78.18 L 542 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 477 113.36 C 477 109.57 483.72 106.5 492 106.5 C 495.98 106.5 499.79 107.22 502.61 108.51 C 505.42 109.79 507 111.54 507 113.36 L 507 144.64 C 507 148.43 500.28 151.5 492 151.5 C 483.72 151.5 477 148.43 477 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 507 113.36 C 507 117.14 500.28 120.21 492 120.21 C 483.72 120.21 477 117.14 477 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 597 106.5 Q 597 87.78 570.75 87.78 Q 544.5 87.78 544.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 544.5 70.68 L 547 78.18 L 542 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 582 113.36 C 582 109.57 588.72 106.5 597 106.5 C 600.98 106.5 604.79 107.22 607.61 108.51 C 610.42 109.79 612 111.54 612 113.36 L 612 144.64 C 612 148.43 605.28 151.5 597 151.5 C 588.72 151.5 582 148.43 582 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 612 113.36 C 612 117.14 605.28 120.21 597 120.21 C 588.72 120.21 582 117.14 582 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 709.5 106.5 Q 709.5 87.78 739.5 87.78 Q 769.5 87.78 769.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 769.5 70.68 L 772 78.18 L 767 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 694.5 113.36 C 694.5 109.57 701.22 106.5 709.5 106.5 C 713.48 106.5 717.29 107.22 720.11 108.51 C 722.92 109.79 724.5 111.54 724.5 113.36 L 724.5 144.64 C 724.5 148.43 717.78 151.5 709.5 151.5 C 701.22 151.5 694.5 148.43 694.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 724.5 113.36 C 724.5 117.14 717.78 120.21 709.5 120.21 C 701.22 120.21 694.5 117.14 694.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 829.5 106.5 Q 829.5 87.78 799.5 87.78 Q 769.5 87.78 769.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 769.5 70.68 L 772 78.18 L 767 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 814.5 113.36 C 814.5 109.57 821.22 106.5 829.5 106.5 C 833.48 106.5 837.29 107.22 840.11 108.51 C 842.92 109.79 844.5 111.54 844.5 113.36 L 844.5 144.64 C 844.5 148.43 837.78 151.5 829.5 151.5 C 821.22 151.5 814.5 148.43 814.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 844.5 113.36 C 844.5 117.14 837.78 120.21 829.5 120.21 C 821.22 120.21 814.5 117.14 814.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 259.5 106.5 Q 259.5 87.78 297 87.78 Q 334.5 87.78 334.5 78.18" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 334.5 70.68 L 337 78.18 L 332 78.18 Z" fill="#666666" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 244.5 113.36 C 244.5 109.57 251.22 106.5 259.5 106.5 C 263.48 106.5 267.29 107.22 270.11 108.51 C 272.92 109.79 274.5 111.54 274.5 113.36 L 274.5 144.64 C 274.5 148.43 267.78 151.5 259.5 151.5 C 251.22 151.5 244.5 148.43 244.5 144.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 274.5 113.36 C 274.5 117.14 267.78 120.21 259.5 120.21 C 251.22 120.21 244.5 117.14 244.5 113.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 229.5 99 L 218.25 99 Q 207 99 207 114 L 207 121.5 Q 207 129 195.75 129 L 190.13 129 Q 184.5 129 195.75 129 L 201.38 129 Q 207 129 207 144 L 207 151.5 Q 207 159 218.25 159 L 229.5 159" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="all"/>
|
||||
<rect x="19.5" y="286.5" width="165" height="45" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 206px; margin-left: 13px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
<span style="">
|
||||
Horizontally Scaled
|
||||
</span>
|
||||
<br style="border-color: var(--border-color);"/>
|
||||
<span style="">
|
||||
Deployments
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="121" y="210" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
|
||||
Horizontally Scale...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="19.5" y="106.5" width="165" height="45" fill="none" stroke="none" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 86px; margin-left: 13px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
|
||||
Logical Databases
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="121" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
|
||||
Logical Databases
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 319.5 53.36 C 319.5 49.57 326.22 46.5 334.5 46.5 C 338.48 46.5 342.29 47.22 345.11 48.51 C 347.92 49.79 349.5 51.54 349.5 53.36 L 349.5 62.14 C 349.5 65.93 342.78 69 334.5 69 C 326.22 69 319.5 65.93 319.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 349.5 53.36 C 349.5 57.14 342.78 60.21 334.5 60.21 C 326.22 60.21 319.5 57.14 319.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 319.5 45.86 C 319.5 42.07 326.22 39 334.5 39 C 338.48 39 342.29 39.72 345.11 41.01 C 347.92 42.29 349.5 44.04 349.5 45.86 L 349.5 54.64 C 349.5 58.43 342.78 61.5 334.5 61.5 C 326.22 61.5 319.5 58.43 319.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 349.5 45.86 C 349.5 49.64 342.78 52.71 334.5 52.71 C 326.22 52.71 319.5 49.64 319.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 319.5 38.36 C 319.5 34.57 326.22 31.5 334.5 31.5 C 338.48 31.5 342.29 32.22 345.11 33.51 C 347.92 34.79 349.5 36.54 349.5 38.36 L 349.5 47.14 C 349.5 50.93 342.78 54 334.5 54 C 326.22 54 319.5 50.93 319.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 349.5 38.36 C 349.5 42.14 342.78 45.21 334.5 45.21 C 326.22 45.21 319.5 42.14 319.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 529.5 53.36 C 529.5 49.57 536.22 46.5 544.5 46.5 C 548.48 46.5 552.29 47.22 555.11 48.51 C 557.92 49.79 559.5 51.54 559.5 53.36 L 559.5 62.14 C 559.5 65.93 552.78 69 544.5 69 C 536.22 69 529.5 65.93 529.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 559.5 53.36 C 559.5 57.14 552.78 60.21 544.5 60.21 C 536.22 60.21 529.5 57.14 529.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 529.5 45.86 C 529.5 42.07 536.22 39 544.5 39 C 548.48 39 552.29 39.72 555.11 41.01 C 557.92 42.29 559.5 44.04 559.5 45.86 L 559.5 54.64 C 559.5 58.43 552.78 61.5 544.5 61.5 C 536.22 61.5 529.5 58.43 529.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 559.5 45.86 C 559.5 49.64 552.78 52.71 544.5 52.71 C 536.22 52.71 529.5 49.64 529.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 529.5 38.36 C 529.5 34.57 536.22 31.5 544.5 31.5 C 548.48 31.5 552.29 32.22 555.11 33.51 C 557.92 34.79 559.5 36.54 559.5 38.36 L 559.5 47.14 C 559.5 50.93 552.78 54 544.5 54 C 536.22 54 529.5 50.93 529.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 559.5 38.36 C 559.5 42.14 552.78 45.21 544.5 45.21 C 536.22 45.21 529.5 42.14 529.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 754.5 53.36 C 754.5 49.57 761.22 46.5 769.5 46.5 C 773.48 46.5 777.29 47.22 780.11 48.51 C 782.92 49.79 784.5 51.54 784.5 53.36 L 784.5 62.14 C 784.5 65.93 777.78 69 769.5 69 C 761.22 69 754.5 65.93 754.5 62.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 784.5 53.36 C 784.5 57.14 777.78 60.21 769.5 60.21 C 761.22 60.21 754.5 57.14 754.5 53.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 754.5 45.86 C 754.5 42.07 761.22 39 769.5 39 C 773.48 39 777.29 39.72 780.11 41.01 C 782.92 42.29 784.5 44.04 784.5 45.86 L 784.5 54.64 C 784.5 58.43 777.78 61.5 769.5 61.5 C 761.22 61.5 754.5 58.43 754.5 54.64 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 784.5 45.86 C 784.5 49.64 777.78 52.71 769.5 52.71 C 761.22 52.71 754.5 49.64 754.5 45.86" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 754.5 38.36 C 754.5 34.57 761.22 31.5 769.5 31.5 C 773.48 31.5 777.29 32.22 780.11 33.51 C 782.92 34.79 784.5 36.54 784.5 38.36 L 784.5 47.14 C 784.5 50.93 777.78 54 769.5 54 C 761.22 54 754.5 50.93 754.5 47.14 Z" fill="#f5f5f5" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 784.5 38.36 C 784.5 42.14 777.78 45.21 769.5 45.21 C 761.22 45.21 754.5 42.14 754.5 38.36" fill="none" stroke="#666666" stroke-width="1.5" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 229.5 20.25 L 218.25 20.25 Q 207 20.25 207 35.25 L 207 42.75 Q 207 50.25 195.75 50.25 L 190.13 50.25 Q 184.5 50.25 195.75 50.25 L 201.38 50.25 Q 207 50.25 207 65.25 L 207 72.75 Q 207 80.25 218.25 80.25 L 229.5 80.25" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)scale(1.5)">
|
||||
<switch>
|
||||
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 108px; height: 1px; padding-top: 34px; margin-left: 13px;">
|
||||
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
|
||||
DBMS Instances
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="121" y="37" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
|
||||
DBMS Instances
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
|
||||
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||
Text is not SVG - cannot display
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 46 KiB |
@@ -140,3 +140,13 @@ backend.start();
|
||||
```
|
||||
|
||||
We've now split the backend into two separate deployments, but we still need to make sure that they can communicate with each other. This is the hard and somewhat tedious part, as Backstage currently doesn't provide an out of the box solution that solves this. You'll need to manually configure the two backends with custom implementations of the `DiscoveryService` and have them return the correct URLs for each other. Likewise, you'll also need to provide a custom implementation of the `DiscoveryApi` in the frontend, unless you surface the two backends via a proxy that handles the routing instead.
|
||||
|
||||
### Split backend deployments architecture example
|
||||
|
||||
Below is an example of a more elaborate setup where we have three different backend deployments, each with their own set of plugins and modules. Between our frontend app and the backend instances we have a reverse proxy that routes the traffic to the appropriate instance. As an option for securing the Backstage deployment the proxy can be set up as an authenticating reverse proxy as well, denying unauthenticated users access to the backend instances.
|
||||
|
||||

|
||||
|
||||
In this example we have split out the Catalog and Search plugins into one backend deployment. The proxy routes all traffic for `/api/catalog/` and `/api/search/` to this instance. With this separation we're able to scale and deploy these two plugins independently, and they are also isolated from both a performance and security perspective. Likewise the TechDocs and Scaffolder plugins are split out as well, and then we route the rest of the traffic to our instance that contains the App, Auth, and Proxy plugins.
|
||||
|
||||
We also see how each of the plugins have their own logical database, but are often set up to share the actual Database Management System (DBMS) instance. This is of course not a requirement, and you can choose to further divide or consolidate the databases as you see fit.
|
||||
|
||||
@@ -754,3 +754,255 @@ going easily, but feel free to move it out to where it fits best. As you migrate
|
||||
your entire plugin flora to the new backend system, you will probably make more
|
||||
and more of these modules as "first class" things, living right next to the
|
||||
implementations that they represent, and being exported from there.
|
||||
|
||||
### The Auth Plugin
|
||||
|
||||
A basic installation of the auth plugin with a microsoft provider will look as follows.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
An additional step you'll need to take is to add the resolvers to your configuration, here's an example:
|
||||
|
||||
```yaml title:"app-config.yaml"
|
||||
auth:
|
||||
environment: development
|
||||
providers:
|
||||
microsoft:
|
||||
development:
|
||||
clientId: ${AZURE_CLIENT_ID}
|
||||
clientSecret: ${AZURE_CLIENT_SECRET}
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
> Note: the resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
#### Auth Plugin Modules and Their Resolvers
|
||||
|
||||
As you may have noticed in the above example you'll need to import the `auth-backend` and an `auth-backend-module`. The following sections outline each of them and their resolvers.
|
||||
|
||||
All of the following modules include the following common resolvers:
|
||||
|
||||
- [emailMatchingUserEntityProfileEmail](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L29)
|
||||
- [emailLocalPartMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L54)
|
||||
|
||||
##### Atlassian
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts#L33C16-L33C46)
|
||||
|
||||
##### GCP IAM
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gcp-iap-provider/src/resolvers.ts#L32C16-L32C49)
|
||||
|
||||
##### GitHub
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-github-provider/src/resolvers.ts#L33C16-L33C46)
|
||||
|
||||
##### GitLab
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gitlab-provider/src/resolvers.ts#L33C16-L33C46)
|
||||
|
||||
##### Google
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-google-provider/src/resolvers.ts#L33C16-L33C49)
|
||||
|
||||
##### Microsoft
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-microsoft-provider/src/resolvers.ts#L33C16-L33C49)
|
||||
|
||||
##### oauth2
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-oauth2-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-provider/src/resolvers.ts#L33C16-L33C46)
|
||||
|
||||
##### oauth2 Proxy
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [forwardedUserMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts#L27C16-L27C51)
|
||||
|
||||
##### Okta
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-okta-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-okta-provider/src/resolvers.ts#L34C16-L34C49)
|
||||
|
||||
##### Pinniped
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
##### VMware Cloud
|
||||
|
||||
Setup:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Additional resolvers:
|
||||
|
||||
- [vmwareCloudSignInResolvers](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts#L29C18-L29C44)
|
||||
|
||||
#### Custom Resolver
|
||||
|
||||
You may have a case where the common resolvers or the ones that are included with the auth module you use won't work for your needs. In this case you will need to create a custom resolver. Instead of the 2nd import for your auth provider module you would provide your own:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
/* highlight-add-start */
|
||||
export const authModuleGoogleProvider = createBackendModule({
|
||||
pluginId: 'auth',
|
||||
moduleId: 'googleProvider',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: { providers: authProvidersExtensionPoint },
|
||||
async init({ providers }) {
|
||||
providers.registerProvider({
|
||||
providerId: 'google',
|
||||
factory: createOAuthProviderFactory({
|
||||
authenticator: googleAuthenticator,
|
||||
async signInResolver(info, ctx) {
|
||||
// custom resolver ...
|
||||
},
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
/* highlight-add-end */
|
||||
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
backend.add(authModuleGoogleProvider);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
@@ -130,7 +130,7 @@ export class CustomClustersSupplier implements KubernetesClustersSupplier {
|
||||
|
||||
static create(refreshInterval: Duration) {
|
||||
const clusterSupplier = new CustomClustersSupplier();
|
||||
// setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/search-backend-node/src/runPeriodically.ts
|
||||
// setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/kubernetes-backend/src/service/runPeriodically.ts
|
||||
runPeriodically(
|
||||
() => clusterSupplier.refreshClusters(),
|
||||
refreshInterval.toMillis(),
|
||||
|
||||
@@ -51,18 +51,19 @@ _Example disabling the search page extension_
|
||||
# app-config.yaml
|
||||
app:
|
||||
extensions:
|
||||
- plugin.search.page: false # ✨
|
||||
- page:search: false # ✨
|
||||
- nav-item:search: false # ✨
|
||||
```
|
||||
|
||||
_Example setting the search sidebar item label_
|
||||
_Example setting the search sidebar item title_
|
||||
|
||||
```yaml
|
||||
# app-config.yaml
|
||||
app:
|
||||
extensions:
|
||||
- plugin.search.nav.index: # ✨
|
||||
- nav-item:search: # ✨
|
||||
config:
|
||||
label: 'Search Page'
|
||||
title: 'Search Page'
|
||||
```
|
||||
|
||||
> **Known limitations:**
|
||||
|
||||
@@ -782,7 +782,7 @@ Describes the following entity kind:
|
||||
|
||||
An API describes an interface that can be exposed by a component. The API can be
|
||||
defined in different formats, like [OpenAPI](https://swagger.io/specification/),
|
||||
[AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/),
|
||||
[AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest),
|
||||
[GraphQL](https://graphql.org/learn/schema/),
|
||||
[gRPC](https://developers.google.com/protocol-buffers), or other formats.
|
||||
|
||||
@@ -838,7 +838,7 @@ The current set of well-known and common values for this field is:
|
||||
- `openapi` - An API definition in YAML or JSON format based on the
|
||||
[OpenAPI](https://swagger.io/specification/) version 2 or version 3 spec.
|
||||
- `asyncapi` - An API definition based on the
|
||||
[AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/) spec.
|
||||
[AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest) spec.
|
||||
- `graphql` - An API definition based on
|
||||
[GraphQL schemas](https://spec.graphql.org/) for consuming
|
||||
[GraphQL](https://graphql.org/) based APIs.
|
||||
|
||||
@@ -128,10 +128,10 @@ class ExamplePermissionPolicy implements PermissionPolicy {
|
||||
}
|
||||
```
|
||||
|
||||
With this permission policy, the user `spiderman` won't be able to execute the debug:log action.
|
||||
With this permission policy, the user `spiderman` won't be able to execute the `debug:log` action.
|
||||
|
||||
You can also restrict the input provided to the action by combining multiple rules.
|
||||
In the example below, `spiderman` won't be able to execute debug:log when passing `{ "message": "not-this!" }` as action input:
|
||||
In the example below, `spiderman` won't be able to execute `debug:log` when passing `{ "message": "not-this!" }` as action input:
|
||||
|
||||
```ts title="packages/backend/src/plugins/permission.ts"
|
||||
/* highlight-add-start */
|
||||
|
||||
@@ -60,7 +60,7 @@ Extensions are created using the `createExtension` function from `@backstage/fro
|
||||
|
||||
```tsx
|
||||
const extension = createExtension({
|
||||
id: 'my-extension',
|
||||
name: 'my-extension',
|
||||
// This is the attachment point, `id` is the ID of the parent extension,
|
||||
// while `input` is the name of the input to attach to.
|
||||
attachTo: { id: 'my-parent', input: 'content' },
|
||||
@@ -71,10 +71,10 @@ const extension = createExtension({
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
// This factory is called to instantiate the extensions and produce its output.
|
||||
factory({ bind }) {
|
||||
bind({
|
||||
factory() {
|
||||
return {
|
||||
element: <div>Hello World</div>,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -85,68 +85,288 @@ Note that while the `createExtension` is public API and used in many places, it
|
||||
|
||||
## Extension Data
|
||||
|
||||
TODO
|
||||
Communication between extensions happens in one direction, from one child extension through the attachment point to its parent. The child extension outputs data which is then passed as inputs to the parent extension. This data is called Extension Data, where the shape of each individual piece of data is described by an Extension Data Reference. These references are created separately from the extensions themselves, and can be shared across multiple different kinds of extensions. Each reference consists of an ID and a TypeScript type that the data needs to conform to, and represents one type of data that can be shared between extensions.
|
||||
|
||||
### Extension Data References
|
||||
|
||||
To create a new extension data reference to represent a type of shared extension data you use the `createExtensionDataRef` function. When defining a new reference you need to provide an ID and a TypeScript type, for example:
|
||||
|
||||
```ts
|
||||
export const reactElementExtensionDataRef =
|
||||
createExtensionDataRef<React.JSX.Element>('my-plugin.reactElement');
|
||||
```
|
||||
|
||||
The `ExtensionDataRef` can then be used to describe an output property of the extension. This will enforce typing on the return value of the extension factory:
|
||||
|
||||
```tsx
|
||||
const extension = createExtension({
|
||||
// ...
|
||||
output: {
|
||||
element: reactElementExtensionDataRef,
|
||||
},
|
||||
factory() {
|
||||
return {
|
||||
element: <div>Hello World</div>,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Extension Data Uniqueness
|
||||
|
||||
Note that the key used in the output map, in this case `element`, is only used internally within the definition of the extension itself. That actual identifier for the data when consumed by other extensions is the ID of the reference, in this case `core.reactElement`. This means that you can not output multiple different values for the same extension data reference, as they would conflict with each other. That in turn makes overly generic extension data references a bad idea, for example a generic "string" type. Instead create separate references for each type of data that you want to share.
|
||||
|
||||
```tsx
|
||||
const extension = createExtension({
|
||||
// ...
|
||||
output: {
|
||||
// ❌ Bad example - outputting values of same type
|
||||
element1: reactElementExtensionDataRef,
|
||||
element2: reactElementExtensionDataRef,
|
||||
},
|
||||
factory() {
|
||||
return {
|
||||
element1: <div>Hello World</div>,
|
||||
element2: <div>Hello World</div>,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Core Extension Data
|
||||
|
||||
We provide default `coreExtensionData`, which provides commonly used `ExtensionDataRef`s - e.g. for `React.JSX.Element` and `RouteRef`. They can be used when creating your own extension. For example, the React Element extension data that we defined above is already provided as `coreExtensionData.reactElement`.
|
||||
|
||||
<!-- For a full list and explanations of all types of core extension data, see the [core extension data reference](#TODO). -->
|
||||
|
||||
### Optional Extension Data
|
||||
|
||||
By default all extension data is required, meaning that the extension factory must provide a value for each output. However, it is possible to make extension data optional by calling the `.optional()` method. This makes it optional for the factory function to return a value as part of its output. When calling the `.optional()` method you create a new copy of the extension data reference, it does not mutate the existing reference.
|
||||
|
||||
```tsx
|
||||
const extension = createExtension({
|
||||
// ...
|
||||
output: {
|
||||
element: coreExtensionData.reactElement.optional(),
|
||||
},
|
||||
factory() {
|
||||
return {
|
||||
element:
|
||||
Math.random() < 0.5 ? <img src="./assets/logo.png" /> : undefined,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Extension Inputs
|
||||
|
||||
<!--
|
||||
The Extension Data can be passed up to other extensions through their extension inputs. Similar to the outputs seen before, let's create an example an extension with a extension input:
|
||||
|
||||
Introduce the concept of extension inputs and how they use extension data to reference types just like outputs
|
||||
```tsx
|
||||
const navigationExtension = createExtension({
|
||||
// ...
|
||||
inputs: {
|
||||
// [1]: Input
|
||||
logo: createExtensionInput(
|
||||
{
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
{ singleton: true, optional: true },
|
||||
),
|
||||
},
|
||||
factory({ inputs }) {
|
||||
return {
|
||||
element: (
|
||||
<nav>{inputs.logo.output?.element ?? <span>Backstage</span>}</nav>
|
||||
),
|
||||
};
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Show how to use the `createExtensionInput` API to create an input for an extension.
|
||||
The input (see [1] above) is an object that we create using `createExtensionInput`. The first argument is the set of extension data that we accept via this input, and works just like the `output` option. The second argument is optional, and it allows us to put constraints on the extensions that are attached to our input. If the `singleton: true` option is set, only a single extension can attached at a time, and unless the `optional: true` option is set it will also be required that there is exactly on attached extension.
|
||||
|
||||
- Example of creating a single input
|
||||
So how can we now attach the output to the parent extension's input? If we think about a navigation component, like the Sidebar in Backstage, there might be plugins that want to attach a link to their plugin to this navigation component. In this case the plugin only needs to know the extension `id` and the name of the extension `input` to attach the extension `output` returned by the `factory` to the specified extension:
|
||||
|
||||
Talk about different types of inputs, singleton vs array + optional vs required.
|
||||
```tsx
|
||||
const navigationItemExtension = createExtension({
|
||||
// ...
|
||||
attachTo: { id: 'app/nav', input: 'items' },
|
||||
factory() {
|
||||
return {
|
||||
element: <Link to="/home">Home</Link>,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
- Example of creating an optional singleton input - not the value is no longer an array
|
||||
const navigationExtension = createExtension({
|
||||
// ...
|
||||
// [2]: Extension `id` will be `app/nav` following the extension naming pattern
|
||||
namespace: 'app',
|
||||
name: 'nav',
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
inputs: {
|
||||
items: createExtensionInput({
|
||||
element: coreExtensionData.reactElement,
|
||||
}),
|
||||
},
|
||||
factory({ inputs }) {
|
||||
return {
|
||||
element: (
|
||||
<nav>
|
||||
<ul>
|
||||
{inputs.items.map(item => {
|
||||
return <li>{item.output.element}</li>;
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
),
|
||||
};
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Talk about the shape of the input values and that you have access to the AppNode node in addition to the data, but discourage use of AppNode.
|
||||
In this case the extension input `items` is an array, where each individual item is an extension that attached itself to the extension inputs of this `id`.
|
||||
|
||||
- Example of how to access the AppNode next to the input data
|
||||
With the `inputs` not only the `output` of an extensions item is passed to the extension, but also the `node`. However, it is discouraged to consume the `node` here unless needed. If we are looking at the `factory` function from the example above we could access the `node` like the following:
|
||||
|
||||
-->
|
||||
```tsx
|
||||
// ...
|
||||
factory({ inputs }) {
|
||||
return {
|
||||
element: (
|
||||
<nav>
|
||||
<ul>
|
||||
{inputs.items.map(({output, node}) => {
|
||||
const _node: AppNode = node;
|
||||
return <li>{output.element}</li>;
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
),
|
||||
};
|
||||
},
|
||||
```
|
||||
|
||||
## Extension Configuration
|
||||
|
||||
<!--
|
||||
With the `app-config.yaml` there is already the option to pass configuration to plugins or the app to e.g. define the `baseURL` of your app. For extensions this concept would be limiting as an extension can be independent of the plugin & initiated several times. Therefor we created a possibility to configure each extension individually through config. The extension config schema is created using the [`zod`](https://zod.dev/) library, which in addition to TypeScript type checking also provides runtime validation and coercion. If we continue with the example of the `navigationExtension` and now want it to contain a configurable title, we could make it available like the following:
|
||||
|
||||
Introduce the concept of extension configuration, highlight that it's different from app config
|
||||
```tsx
|
||||
const navigationExtension = createExtension({
|
||||
// ...
|
||||
namespace: 'app',
|
||||
name: 'nav',
|
||||
// [3]: Extension `id` will be `app/nav` following the extension naming pattern
|
||||
configSchema: createSchemaFromZod(z =>
|
||||
z.object({
|
||||
title: z.string().default('Sidebar Title'),
|
||||
}),
|
||||
),
|
||||
factory({ config }) {
|
||||
return {
|
||||
element: (
|
||||
<nav>
|
||||
<span>{config.title}</span>
|
||||
<ul>{/* ... */}</ul>
|
||||
</nav>
|
||||
),
|
||||
};
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Show how to define a configuration schema for an extension, talk about it using zod (link to zod), in general explain everything there is to know about the schema
|
||||
To now change the text of the title from "Sidebar Title" to "Backstage" we can look at the `id` of the extension & add the following to the `app-config.yaml`:
|
||||
|
||||
- Example that creates a configuration schema for an extension
|
||||
|
||||
Show how to provide configuration for an extension - keep this part short, and instead link to the architecture section that talks about writing configuration
|
||||
|
||||
- One example of a YAML configurations for the above extension
|
||||
|
||||
-->
|
||||
```yaml
|
||||
app:
|
||||
# ...
|
||||
extensions:
|
||||
# ...
|
||||
- app/nav:
|
||||
config:
|
||||
title: 'Backstage'
|
||||
```
|
||||
|
||||
## Extension Creators
|
||||
|
||||
<!--
|
||||
With creating an extension by using `createExtension(...)` you have the advantage that the extension can be anything in your Backstage application. We realised that this comes with the trade-off of having to repeat boilerplate code for similar building blocks. Here extension creators come into play for covering common building blocks in Backstage like pages using `createPageExtension`, themes using the `createThemeExtension` or items for the navigation using `createNavItemExtension`.
|
||||
|
||||
Introduce the concept of extension creators, talk about how they are used to provide an opinionated way of creating extensions for specific use cases. Mention a few of the built-in creators, link to the reference section on built-in extension kinds (TBD).
|
||||
If we follow the example from above all items of the navigation have similarities, like they all want to be attached to the same extension with the same input as well as rendering the same navigation item component. Therefor `createExtension` can be abstracted for this use case to `createNavItemExtension` and if we add the extension to the app it will end up in the right place & looks like we expect a navigation item to look.
|
||||
|
||||
- Example of using an existing extension creator to create an extension
|
||||
```tsx
|
||||
export const HomeNavIcon = createNavItemExtension({
|
||||
routeRef: routeRefForTheHomePage,
|
||||
title: 'Home',
|
||||
icon: HomeIcon,
|
||||
});
|
||||
```
|
||||
|
||||
Explain that each extension creator creates a specific "kind" of extensions - introduce the concept of extension kinds. Show an example of how the kind is used to build up the ID.
|
||||
### Extension Kind
|
||||
|
||||
- Example of creating a new extension creator for creating a specific kind of extension
|
||||
With the example `HomeNavIcon` will end up on the extension input `items` of the extensions with the id `app/nav`. It raises the question what the `id` of the `HomeNavIcon` itself is. The extension creator for the navigation item has a defined `kind`, which by convention matches the own name. So in this example `createNavItemExtension` sets the kind to `nav-item`.
|
||||
|
||||
Explain that extension creators should be exported from library packages (`-react`) rather than plugin packages.
|
||||
The `id` of the extension is then build out of `namespace`, `name` & `kind` like the following - where `namespace` & `name` are optional properties that can be passed to the extension creator:
|
||||
|
||||
-->
|
||||
```
|
||||
id: kind:namespace/name
|
||||
```
|
||||
|
||||
For more information on naming of extension refer to the [naming patterns documentation](./08-naming-patterns.md).
|
||||
|
||||
### Extension Creators in libraries
|
||||
|
||||
Extension creators should be exported from frontend library packages (e.g. `*-react`) rather than plugin packages.
|
||||
|
||||
If an extension is only for in-house tweaks, it's okay to put it in the plugin package. But if you want other open source plugins to use it, or you already have a `-react` package, always put extension creators in the `-react` package.
|
||||
|
||||
## Extension Boundary
|
||||
|
||||
<!--
|
||||
The `ExtensionBoundary` wraps extensions with several React contexts for different purposes
|
||||
|
||||
Introduce the need for extension specific React contexts, for example error boundaries and analytics.
|
||||
### Suspense
|
||||
|
||||
Any React elements that are rendered by extension creators should be wrapped in the `ExtensionBoundary`
|
||||
All React elements rendered by extension creators should be wrapped in the extension boundary. With `Suspense` the extension can than load resources asynchronously with having a loading fallback. It also allows to lazy load the whole extension similar to how plugins are currently lazy loaded in Backstage.
|
||||
|
||||
- Example of how to use the `ExtensionBoundary` in an extension creator
|
||||
### Error Boundary
|
||||
|
||||
-->
|
||||
Similar to plugins the `ErrorBoundary` for extension allows to pass in a fallback component in case there is an uncaught error inside of the component. With this the error can be isolated & it would prevent the rest of the plugin to crash.
|
||||
|
||||
### Analytics
|
||||
|
||||
Analytics information are provided through the `AnalyticsContext`, which will give `extensionId` & `pluginId` as context to analytics event fired inside of the extension. Additionally `RouteTracker` will capture an analytics event for routable extension to inform which extension metadata gets associated with a navigation event when the route navigated to is a gathered `mountPoint`.
|
||||
|
||||
The `ExtensionBoundary` can be used like the following in an extension creator:
|
||||
|
||||
```tsx
|
||||
export function createSomeExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
>(options): ExtensionDefinition<TConfig> {
|
||||
return createExtension({
|
||||
// ...
|
||||
factory({ config, inputs, node }) {
|
||||
const ExtensionComponent = lazy(() =>
|
||||
options
|
||||
.loader({ config, inputs })
|
||||
.then(element => ({ default: () => element })),
|
||||
);
|
||||
|
||||
return {
|
||||
path: config.path,
|
||||
routeRef: options.routeRef,
|
||||
element: (
|
||||
<ExtensionBoundary node={node} routable>
|
||||
<ExtensionComponent />
|
||||
</ExtensionBoundary>
|
||||
),
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
id: 01-getting-started
|
||||
title: Schema-first plugins with OpenAPI (Experimental)
|
||||
description: Tutorial on how to start using OpenAPI schema-first development in your plugins.
|
||||
---
|
||||
|
||||
# Getting started with OpenAPI in your Backstage plugins
|
||||
|
||||
Target Audience: Plugin developers
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
## Goal
|
||||
|
||||
The goal of this tutorial is to give you exposure to tools that more tightly couple your OpenAPI specification and plugin lifecycle. The tools we'll be presenting were created by the OpenAPI tooling project area and allow you to create,
|
||||
|
||||
1. A typed `express` router that provides strong guardrails during development for input and output values. Support for query, path parameters and request body, as well as experimental support for headers and cookies.
|
||||
2. An auto-generated client to interact with your plugin's backend. Support for all request types, parameters and body, as well as return types. Provides a low-level interface to allow more customization by higher level libraries.
|
||||
3. Validation and verification tooling to ensure your API and specification stay in sync. Includes testing against your unit tests.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Technical Knowledge
|
||||
|
||||
This tutorial assumes that you're already familiar with the following,
|
||||
|
||||
1. How to build a Backstage plugin.
|
||||
2. `Express.js` and `Typescript`
|
||||
3. OpenAPI 3.0 schemas
|
||||
|
||||
### Setting up
|
||||
|
||||
There are two required npm packages before we start,
|
||||
|
||||
1. `@backstage/repo-tools`, this package contains all OpenAPI related commands for your plugins. We will be using this throughout the tutorial.
|
||||
2. `@opticdev/optic`, this package is a dependency of `@backstage/repo-tools` but is only required for OpenAPI related commands.
|
||||
|
||||
You should install both of the above packages in the _root_ of your workspace.
|
||||
|
||||
## Storing your OpenAPI specification
|
||||
|
||||
You should create a new folder, `src/schema` in your backend plugin to store your OpenAPI (and any other) specifications. For example, if you're adding a specification to the catalog plugin, you would add a `src/schema` folder to `plugins/catalog-backend`, making a `plugins/catalog-backend/src/schema` directory. This directory should have an `openapi.yaml` file inside.
|
||||
|
||||
> Currently, only the `.yaml` extension is supported, not `.yml`.
|
||||
|
||||
## Generating a typed express router from a spec
|
||||
|
||||
Run `yarn backstage-repo-tools schema openapi generate <plugin-directory>`. This will create an `openapi.generated.ts` file in the `src/schema` directory that contains the OpenAPI schema as well as a generated express router with types.
|
||||
|
||||
Use it like so, update your `router.ts` or `createRouter.ts` file with the following content,
|
||||
|
||||
```diff
|
||||
+ import { createOpenApiRouter } from '../schema/openapi.generated';
|
||||
- import Router from 'express-promise-router';
|
||||
|
||||
...
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
+ const router = await createOpenApiRouter();
|
||||
- const router = Router();
|
||||
```
|
||||
|
||||
## Generating a typed client from a spec
|
||||
|
||||
Run `yarn backstage-repo-tools schema openapi generate-client --input-spec <plugin-directory>/src/schema/openapi.yaml --output-directory <plugin-client-directory>`. `<plugin-directory>` should match the same backend plugin we've been using so far. `<plugin-client-directory>` is a new directory and npm package that you should create. The general pattern is `plugins/<plugin-name>-client`.
|
||||
|
||||
The generated client will have a directory `src/generated` that exports a `DefaultApiClient` class and all generated types. You can use the client like so,
|
||||
|
||||
```diff
|
||||
+ import { DefaultApiClient } from './generated';
|
||||
|
||||
export class CatalogClient implements CatalogApi {
|
||||
+ private readonly apiClient: DefaultApiClient;
|
||||
|
||||
constructor(options: {
|
||||
discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };
|
||||
fetchApi?: { fetch: typeof fetch };
|
||||
}) {
|
||||
+ this.apiClient = new DefaultApiClient(options);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
usage of the types will depend on your type names.
|
||||
|
||||
You should be able to use the generated `DefaultApi.client.ts` file out of the box for your API needs. For full customization, you can use a wrapper around the generated client to adjust the flavor of your clients.
|
||||
|
||||
For more information, see [the docs](./generate-client.md).
|
||||
|
||||
## Validating your spec with test traffic
|
||||
|
||||
Add the following lines to your `createRouter.test.ts` or `router.test.ts` file,
|
||||
|
||||
```diff
|
||||
+ import { wrapInOpenApiTestServer } from '@backstage/backend-openapi-utils';
|
||||
+ import { Server } from 'http';
|
||||
|
||||
...
|
||||
|
||||
describe('createRouter', () => {
|
||||
- let app: express.Express;
|
||||
+ let app: express.Express | Server;
|
||||
|
||||
...
|
||||
|
||||
- app = express().use(router);
|
||||
+ app = wrapInOpenApiTestServer(express().use(router));
|
||||
```
|
||||
|
||||
This adds a wrapper around the express server that allows it to reroute traffic for `supertest`. Run `yarn backstage-repo-tools schema openapi init` to create some required config files. Now, when you run `yarn backstage-repo-tools schema openapi test` your schema will now be tested against your test data. Any errors will be reported.
|
||||
|
||||
Our command is a small wrapper over [`Optic`](https://github.com/opticdev/optic) which does all of the heavy lifting.
|
||||
|
||||
For more information, see [the docs](./test-case-validation.md).
|
||||
@@ -1,3 +1,9 @@
|
||||
---
|
||||
id: generate-client
|
||||
title: Generate a client from your OpenAPI spec
|
||||
description: Documentation on how to create a client for a given OpenAPI spec
|
||||
---
|
||||
|
||||
## How to generate a client with `repo-tools schema openapi generate-client`?
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
---
|
||||
id: test-case-validation
|
||||
title: Validate your OpenAPI spec against test data
|
||||
description: Documentation on how to use the `schema openapi test` command.
|
||||
---
|
||||
|
||||
## OpenAPI Validation using Test Cases
|
||||
|
||||
This is primarily performed by `backstage-repo-tools schema openapi test`. Any errors found in the generated specs can be either
|
||||
|
||||
@@ -158,7 +158,7 @@ package export.
|
||||
|
||||
The Backstage project uses [Node.js](https://nodejs.org/) for both its development
|
||||
tooling and backend runtime. In order for expectations to be clear we use the
|
||||
following schedule for determining the [Node.js releases](https://nodejs.org/en/about/releases/) that we support:
|
||||
following schedule for determining the [Node.js releases](https://nodejs.org/en/about/previous-releases) that we support:
|
||||
|
||||
- At any given point in time we support exactly two adjacent even-numbered
|
||||
releases of Node.js, for example v12 and v14.
|
||||
|
||||
@@ -8,9 +8,17 @@ For some use cases, you may want to define custom [rules](./concepts.md#resource
|
||||
|
||||
## Define a custom rule
|
||||
|
||||
Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule in `packages/backend/src/customPermissionRules/isInSystem.ts`, but you can put it anywhere that's accessible by your `backend` package.
|
||||
Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule and create a condition in `packages/backend/src/plugins/permission.ts`.
|
||||
|
||||
We use Zod in our example below. To install, run:
|
||||
|
||||
```bash
|
||||
yarn workspace backend add zod
|
||||
```
|
||||
|
||||
```typescript title="packages/backend/src/plugins/permission.ts"
|
||||
...
|
||||
|
||||
```typescript title="packages/backend/src/customPermissionRules/isInSystem.ts"
|
||||
import type { Entity } from '@backstage/catalog-model';
|
||||
import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
|
||||
import { createConditionFactory } from '@backstage/plugin-permission-node';
|
||||
@@ -40,43 +48,56 @@ export const isInSystemRule = createCatalogPermissionRule({
|
||||
}),
|
||||
});
|
||||
|
||||
export const isInSystemRuleFactory = createConditionFactory(isInSystemRule);
|
||||
const isInSystem = createConditionFactory(isInSystemRule);
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
For a more detailed explanation on defining rules, refer to the [documentation for plugin authors](./plugin-authors/03-adding-a-resource-permission-check.md#adding-support-for-conditional-decisions).
|
||||
|
||||
## Provide the rule during plugin setup
|
||||
|
||||
Now that we have a custom rule defined, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime.
|
||||
|
||||
The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`.
|
||||
|
||||
```typescript title="packages/backend/src/plugins/catalog.ts"
|
||||
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
||||
import { isInSystemRule } from '../customPermissionRules/isInSystem';
|
||||
|
||||
...
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
builder.addPermissionRules(isInSystemRule);
|
||||
...
|
||||
return router;
|
||||
}
|
||||
```
|
||||
|
||||
The new rule is now ready for use in a permission policy!
|
||||
|
||||
## Use the rule in a policy
|
||||
|
||||
Let's bring this all together by extending the example policy from the previous section.
|
||||
Still in the `packages/backend/src/plugins/permission.ts` file, let's use the condition we just created in our `TestPermissionPolicy`.
|
||||
|
||||
```ts title="packages/backend/src/plugins/permission.ts"
|
||||
...
|
||||
/* highlight-remove-next-line */
|
||||
import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
|
||||
/* highlight-add-next-line */
|
||||
import { isInSystemRuleFactory } from '../customPermissionRules/isInSystem';
|
||||
import { catalogConditions, createCatalogConditionalDecision, createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
|
||||
/* highlight-remove-next-line */
|
||||
import { createConditionFactory } from '@backstage/plugin-permission-node';
|
||||
/* highlight-add-next-line */
|
||||
import { PermissionPolicy, PolicyQuery, createConditionFactory } from '@backstage/plugin-permission-node';
|
||||
/* highlight-add-start */
|
||||
import { BackstageIdentityResponse } from '@backstage/plugin-auth-node';
|
||||
import { AuthorizeResult, PolicyDecision, isResourcePermission } from '@backstage/plugin-permission-common';
|
||||
/* highlight-add-end */
|
||||
...
|
||||
|
||||
export const isInSystemRule = createCatalogPermissionRule({
|
||||
name: 'IS_IN_SYSTEM',
|
||||
description: 'Checks if an entity is part of the system provided',
|
||||
resourceType: 'catalog-entity',
|
||||
paramsSchema: z.object({
|
||||
systemRef: z
|
||||
.string()
|
||||
.describe('SystemRef to check the resource is part of'),
|
||||
}),
|
||||
apply: (resource: Entity, { systemRef }) => {
|
||||
if (!resource.relations) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return resource.relations
|
||||
.filter(relation => relation.type === 'partOf')
|
||||
.some(relation => relation.targetRef === systemRef);
|
||||
},
|
||||
toQuery: ({ systemRef }) => ({
|
||||
key: 'relations.partOf',
|
||||
values: [systemRef],
|
||||
}),
|
||||
});
|
||||
|
||||
const isInSystem = createConditionFactory(isInSystemRule);
|
||||
|
||||
class TestPermissionPolicy implements PermissionPolicy {
|
||||
async handle(
|
||||
@@ -95,11 +116,11 @@ class TestPermissionPolicy implements PermissionPolicy {
|
||||
{
|
||||
anyOf: [
|
||||
catalogConditions.isEntityOwner({
|
||||
claims: user?.identity.ownershipEntityRefs ?? []
|
||||
claims: user?.identity.ownershipEntityRefs ?? [],
|
||||
}),
|
||||
isInSystemRuleFactory({ systemRef: 'interviewing' }),
|
||||
]
|
||||
}
|
||||
isInSystem({ systemRef: 'interviewing' }),
|
||||
],
|
||||
},
|
||||
/* highlight-add-end */
|
||||
);
|
||||
}
|
||||
@@ -111,7 +132,31 @@ class TestPermissionPolicy implements PermissionPolicy {
|
||||
...
|
||||
```
|
||||
|
||||
## Provide the rule during plugin setup
|
||||
|
||||
Now that we have a custom rule defined and added to our policy, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime.
|
||||
|
||||
The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`.
|
||||
|
||||
```typescript title="packages/backend/src/plugins/catalog.ts"
|
||||
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
||||
/* highlight-add-next-line */
|
||||
import { isInSystemRule } from './permission';
|
||||
|
||||
...
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
/* highlight-add-next-line */
|
||||
builder.addPermissionRules(isInSystemRule);
|
||||
...
|
||||
return router;
|
||||
}
|
||||
```
|
||||
|
||||
The updated policy will allow catalog entity resource permissions if any of the following are true:
|
||||
|
||||
- User owns the target entity
|
||||
- Target entity is part of the `'interviewing'` system
|
||||
- Target entity is part of the 'interviewing' system
|
||||
|
||||
@@ -134,3 +134,9 @@ process is used to release an emergency fix as version `6.5.1` in the patch rele
|
||||
- [ ] The fix, which you can likely cherry-pick from your patch branch: `git cherry-pick origin/patch/v1.18.0^`
|
||||
- [ ] An updated `CHANGELOG.md` of all patched packages from the tip of the patch branch, `git checkout origin/patch/v1.18.0 -- {packages,plugins}/*/CHANGELOG.md`. Note that if the patch happens after any next-line releases you'll need to restore those entries in the changelog, placing the patch release entry beneath any next-line release entries.
|
||||
- [ ] A changeset with the message "Applied the fix from version `6.5.1` of this package, which is part of the `v1.18.1` release of Backstage."
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### When the release workflow is not triggered for some reason, such as a GitHub incident
|
||||
|
||||
Ask one of the maintainers to force push master back to a previous commit and then push the release merge commit again.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -204,7 +204,10 @@ module.exports = {
|
||||
{
|
||||
items: [
|
||||
{
|
||||
html: '<a href="/"><h2 class="footerLogo"></h2></a>',
|
||||
html: `
|
||||
<a href="/" aria-label="Backstage Home">
|
||||
<div class="footerLogo"></div>
|
||||
</a>`,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"start": "node scripts/pre-build.js && docusaurus start",
|
||||
"build": "node scripts/pre-build.js && docusaurus build",
|
||||
"prettier:fix": "prettier --write .",
|
||||
"prettier:check": "prettier --check .",
|
||||
"publish-gh-pages": "docusaurus-publish",
|
||||
"write-translations": "docusaurus-write-translations",
|
||||
|
||||
@@ -249,6 +249,15 @@
|
||||
"plugins/internationalization",
|
||||
"plugins/analytics",
|
||||
"plugins/feature-flags",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "OpenAPI",
|
||||
"items": [
|
||||
"openapi/01-getting-started",
|
||||
"openapi/generate-client",
|
||||
"openapi/test-case-validation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Backends and APIs",
|
||||
|
||||
@@ -95,10 +95,12 @@ const HomePage = () => {
|
||||
<img
|
||||
className="laptopSvg"
|
||||
src={`${siteConfig.baseUrl}img/laptop.svg`}
|
||||
alt="Illustration of a laptop"
|
||||
/>
|
||||
<img
|
||||
className="laptopScreenGif"
|
||||
src={`${siteConfig.baseUrl}animations/backstage-logos-hero-8.gif`}
|
||||
alt="Animated Backstage Logo"
|
||||
/>
|
||||
</div>
|
||||
</BannerSectionGrid>
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
--ifm-color-primary-darkest: #268271;
|
||||
}
|
||||
|
||||
#__docusaurus {
|
||||
.theme-doc-markdown {
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footerLogo {
|
||||
background-image: url(/img/logo.svg);
|
||||
background-repeat: no-repeat;
|
||||
|
||||
+58
-48
@@ -2701,82 +2701,90 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.100"
|
||||
"@swc/core-darwin-arm64@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.102"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.100"
|
||||
"@swc/core-darwin-x64@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.102"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.100"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.102"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.102"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.100"
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.102"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.100"
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.102"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.100"
|
||||
"@swc/core-linux-x64-musl@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.102"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.100"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.102"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.100"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.102"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.100"
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.102":
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.102"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.46":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core@npm:1.3.100"
|
||||
version: 1.3.102
|
||||
resolution: "@swc/core@npm:1.3.102"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.3.100
|
||||
"@swc/core-darwin-x64": 1.3.100
|
||||
"@swc/core-linux-arm64-gnu": 1.3.100
|
||||
"@swc/core-linux-arm64-musl": 1.3.100
|
||||
"@swc/core-linux-x64-gnu": 1.3.100
|
||||
"@swc/core-linux-x64-musl": 1.3.100
|
||||
"@swc/core-win32-arm64-msvc": 1.3.100
|
||||
"@swc/core-win32-ia32-msvc": 1.3.100
|
||||
"@swc/core-win32-x64-msvc": 1.3.100
|
||||
"@swc/core-darwin-arm64": 1.3.102
|
||||
"@swc/core-darwin-x64": 1.3.102
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.102
|
||||
"@swc/core-linux-arm64-gnu": 1.3.102
|
||||
"@swc/core-linux-arm64-musl": 1.3.102
|
||||
"@swc/core-linux-x64-gnu": 1.3.102
|
||||
"@swc/core-linux-x64-musl": 1.3.102
|
||||
"@swc/core-win32-arm64-msvc": 1.3.102
|
||||
"@swc/core-win32-ia32-msvc": 1.3.102
|
||||
"@swc/core-win32-x64-msvc": 1.3.102
|
||||
"@swc/counter": ^0.1.1
|
||||
"@swc/types": ^0.1.5
|
||||
peerDependencies:
|
||||
@@ -2786,6 +2794,8 @@ __metadata:
|
||||
optional: true
|
||||
"@swc/core-darwin-x64":
|
||||
optional: true
|
||||
"@swc/core-linux-arm-gnueabihf":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-musl":
|
||||
@@ -2803,7 +2813,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: b68553db388c36b1859f0e8b5231a608277e17ae7fd7a928ea8b448432532176914f84675426d40aa9710617b2e7fb626aaa8358b6b2506b3c43f82db725c41e
|
||||
checksum: 45c0edb06f87a811e28fb3ed587fbe6b7ca67ff2440fe15666d43729788903a4af61e3b57842aecc0b2b70e3c9981b698d8233746ba94dfb5a19e1c62eea33ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3045,9 +3055,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@types/luxon@npm:^3.0.0":
|
||||
version: 3.3.7
|
||||
resolution: "@types/luxon@npm:3.3.7"
|
||||
checksum: 97026557e92bcba308a5592f981591cd200d493fc8997874d79acecf6a2ec41debeded3ac5cd80c371ef7f6f56cc0d1be0a5aca846e03d3e6b4a2be37256fe2f
|
||||
version: 3.3.8
|
||||
resolution: "@types/luxon@npm:3.3.8"
|
||||
checksum: 026711b4aefc01c6e233e359c693b6d4c0873acc3f52a08661ea3751b2cf3e34d1ce1d5b0b99b0e40a059a2a3755acc20498d37db5f9a5a4f0f330cdf72db3db
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5864,12 +5874,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.9":
|
||||
version: 1.15.2
|
||||
resolution: "follow-redirects@npm:1.15.2"
|
||||
version: 1.15.4
|
||||
resolution: "follow-redirects@npm:1.15.4"
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190
|
||||
checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10807,15 +10817,15 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"sass@npm:^1.57.1":
|
||||
version: 1.69.6
|
||||
resolution: "sass@npm:1.69.6"
|
||||
version: 1.69.7
|
||||
resolution: "sass@npm:1.69.7"
|
||||
dependencies:
|
||||
chokidar: ">=3.0.0 <4.0.0"
|
||||
immutable: ^4.0.0
|
||||
source-map-js: ">=0.6.2 <2.0.0"
|
||||
bin:
|
||||
sass: sass.js
|
||||
checksum: 9e98eecd283ce6ca5d75ee233e4ec193cb00706d0e119ab6843c44236d3beed2ba28d0af0b4b6bdb4da76feadf426f559d364a69ae54c010467059d130238a36
|
||||
checksum: c67cd32b69fb26a50e4535353e4145de8cbc8187db07c467cc335157fd56d03cae98754f86efe43b880b29f20c0a168ab972c7f74ebfe234e2bd2dfb868890cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -128,6 +128,10 @@ nav:
|
||||
- Composability System: 'plugins/composability.md'
|
||||
- Plugin Analytics: 'plugins/analytics.md'
|
||||
- Feature Flags: 'plugins/feature-flags.md'
|
||||
- OpenAPI:
|
||||
- Schema-first plugins with OpenAPI (Experimental): 'openapi/01-getting-started.md'
|
||||
- Generate a client from your OpenAPI spec: 'openapi/generate-client.md'
|
||||
- Validate your OpenAPI spec against test data: 'openapi/test-case-validation.md'
|
||||
- Backends and APIs:
|
||||
- Proxying: 'plugins/proxying.md'
|
||||
- Backend plugin: 'plugins/backend-plugin.md'
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
"@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch",
|
||||
"@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch"
|
||||
},
|
||||
"version": "1.22.0-next.0",
|
||||
"version": "1.22.0-next.2",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.4.7-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.2-next.0
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/core-app-api@1.11.3-next.0
|
||||
- @backstage/plugin-permission-react@0.4.19-next.1
|
||||
- @backstage/theme@0.5.0
|
||||
|
||||
## 1.4.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"version": "1.4.7-next.0",
|
||||
"version": "1.4.7-next.1",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# app-next-example-plugin
|
||||
|
||||
## 0.0.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.4.1-next.2
|
||||
|
||||
## 0.0.5-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/frontend-plugin-api@0.4.1-next.1
|
||||
|
||||
## 0.0.5-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "app-next-example-plugin",
|
||||
"description": "Backstage internal example plugin",
|
||||
"version": "0.0.5-next.0",
|
||||
"version": "0.0.5-next.2",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,146 @@
|
||||
# example-app-next
|
||||
|
||||
## 0.0.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-compat-api@0.1.1-next.2
|
||||
- @backstage/plugin-user-settings@0.8.0-next.2
|
||||
- @backstage/plugin-octopus-deploy@0.2.11-next.2
|
||||
- @backstage/frontend-plugin-api@0.4.1-next.2
|
||||
- @backstage/frontend-app-api@0.4.1-next.2
|
||||
- @backstage/plugin-home@0.6.1-next.2
|
||||
- @backstage/plugin-scaffolder-react@1.7.1-next.2
|
||||
- @backstage/plugin-scaffolder@1.17.1-next.2
|
||||
- @backstage/plugin-linguist@0.1.14-next.2
|
||||
- @backstage/plugin-catalog@1.16.1-next.2
|
||||
- @backstage/plugin-catalog-import@0.10.5-next.2
|
||||
- @backstage/plugin-graphiql@0.3.2-next.2
|
||||
- @backstage/plugin-search@1.4.5-next.2
|
||||
- @backstage/plugin-tech-radar@0.6.12-next.2
|
||||
- @backstage/plugin-techdocs@1.9.3-next.2
|
||||
- app-next-example-plugin@0.0.5-next.2
|
||||
- @backstage/plugin-adr@0.6.12-next.2
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.2
|
||||
- @backstage/plugin-explore@0.4.15-next.2
|
||||
- @backstage/plugin-search-react@1.7.5-next.2
|
||||
- @backstage/plugin-visualizer@0.0.2-next.2
|
||||
- @backstage/cli@0.25.1-next.1
|
||||
- @backstage/plugin-pagerduty@0.7.1-next.2
|
||||
- @backstage/plugin-api-docs@0.10.3-next.2
|
||||
- @backstage/plugin-catalog-graph@0.3.3-next.2
|
||||
- @backstage/plugin-org@0.6.19-next.2
|
||||
- @backstage/plugin-airbrake@0.3.29-next.2
|
||||
- @backstage/plugin-azure-devops@0.3.11-next.2
|
||||
- @backstage/plugin-azure-sites@0.1.18-next.2
|
||||
- @backstage/plugin-badges@0.2.53-next.2
|
||||
- @backstage/plugin-cloudbuild@0.3.29-next.2
|
||||
- @backstage/plugin-code-coverage@0.2.22-next.2
|
||||
- @backstage/plugin-cost-insights@0.12.18-next.2
|
||||
- @backstage/plugin-dynatrace@8.0.3-next.2
|
||||
- @backstage/plugin-entity-feedback@0.2.12-next.2
|
||||
- @backstage/plugin-github-actions@0.6.10-next.2
|
||||
- @backstage/plugin-gocd@0.1.35-next.2
|
||||
- @backstage/plugin-jenkins@0.9.4-next.2
|
||||
- @backstage/plugin-kafka@0.3.29-next.2
|
||||
- @backstage/plugin-kubernetes@0.11.4-next.2
|
||||
- @backstage/plugin-lighthouse@0.4.14-next.2
|
||||
- @backstage/plugin-newrelic-dashboard@0.3.4-next.2
|
||||
- @backstage/plugin-playlist@0.2.3-next.2
|
||||
- @backstage/plugin-puppetdb@0.1.12-next.2
|
||||
- @backstage/plugin-rollbar@0.4.29-next.2
|
||||
- @backstage/plugin-sentry@0.5.14-next.2
|
||||
- @backstage/plugin-tech-insights@0.3.21-next.2
|
||||
- @backstage/plugin-todo@0.2.33-next.2
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
|
||||
- @backstage/integration-react@1.1.23-next.0
|
||||
- @backstage/plugin-apache-airflow@0.2.19-next.1
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
|
||||
- @backstage/plugin-devtools@0.1.8-next.1
|
||||
- @backstage/plugin-gcalendar@0.3.22-next.1
|
||||
- @backstage/plugin-gcp-projects@0.3.45-next.1
|
||||
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
|
||||
- @backstage/plugin-newrelic@0.3.44-next.1
|
||||
- @backstage/plugin-shortcuts@0.3.18-next.1
|
||||
- @backstage/plugin-stackstorm@0.1.10-next.1
|
||||
|
||||
## 0.0.5-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-azure-sites@0.1.18-next.1
|
||||
- @backstage/core-plugin-api@1.8.2-next.0
|
||||
- @backstage/plugin-user-settings@0.8.0-next.1
|
||||
- @backstage/plugin-kubernetes@0.11.4-next.1
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/app-defaults@1.4.7-next.1
|
||||
- @backstage/cli@0.25.1-next.1
|
||||
- @backstage/core-app-api@1.11.3-next.0
|
||||
- @backstage/core-compat-api@0.1.1-next.1
|
||||
- @backstage/frontend-app-api@0.4.1-next.1
|
||||
- @backstage/frontend-plugin-api@0.4.1-next.1
|
||||
- @backstage/integration-react@1.1.23-next.0
|
||||
- @backstage/plugin-adr@0.6.12-next.1
|
||||
- @backstage/plugin-airbrake@0.3.29-next.1
|
||||
- @backstage/plugin-apache-airflow@0.2.19-next.1
|
||||
- @backstage/plugin-api-docs@0.10.3-next.1
|
||||
- @backstage/plugin-azure-devops@0.3.11-next.1
|
||||
- @backstage/plugin-badges@0.2.53-next.1
|
||||
- @backstage/plugin-catalog@1.16.1-next.1
|
||||
- @backstage/plugin-catalog-graph@0.3.3-next.1
|
||||
- @backstage/plugin-catalog-import@0.10.5-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.1
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
|
||||
- @backstage/plugin-cloudbuild@0.3.29-next.1
|
||||
- @backstage/plugin-code-coverage@0.2.22-next.1
|
||||
- @backstage/plugin-cost-insights@0.12.18-next.1
|
||||
- @backstage/plugin-devtools@0.1.8-next.1
|
||||
- @backstage/plugin-dynatrace@8.0.3-next.1
|
||||
- @backstage/plugin-entity-feedback@0.2.12-next.1
|
||||
- @backstage/plugin-explore@0.4.15-next.1
|
||||
- @backstage/plugin-gcalendar@0.3.22-next.1
|
||||
- @backstage/plugin-gcp-projects@0.3.45-next.1
|
||||
- @backstage/plugin-github-actions@0.6.10-next.1
|
||||
- @backstage/plugin-gocd@0.1.35-next.1
|
||||
- @backstage/plugin-graphiql@0.3.2-next.1
|
||||
- @backstage/plugin-home@0.6.1-next.1
|
||||
- @backstage/plugin-jenkins@0.9.4-next.1
|
||||
- @backstage/plugin-kafka@0.3.29-next.1
|
||||
- @backstage/plugin-lighthouse@0.4.14-next.1
|
||||
- @backstage/plugin-linguist@0.1.14-next.1
|
||||
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
|
||||
- @backstage/plugin-newrelic@0.3.44-next.1
|
||||
- @backstage/plugin-newrelic-dashboard@0.3.4-next.1
|
||||
- @backstage/plugin-octopus-deploy@0.2.11-next.1
|
||||
- @backstage/plugin-org@0.6.19-next.1
|
||||
- @backstage/plugin-pagerduty@0.7.1-next.1
|
||||
- @backstage/plugin-permission-react@0.4.19-next.1
|
||||
- @backstage/plugin-playlist@0.2.3-next.1
|
||||
- @backstage/plugin-puppetdb@0.1.12-next.1
|
||||
- @backstage/plugin-rollbar@0.4.29-next.1
|
||||
- @backstage/plugin-scaffolder@1.17.1-next.1
|
||||
- @backstage/plugin-scaffolder-react@1.7.1-next.1
|
||||
- @backstage/plugin-search@1.4.5-next.1
|
||||
- @backstage/plugin-search-react@1.7.5-next.1
|
||||
- @backstage/plugin-sentry@0.5.14-next.1
|
||||
- @backstage/plugin-shortcuts@0.3.18-next.1
|
||||
- @backstage/plugin-stackstorm@0.1.10-next.1
|
||||
- @backstage/plugin-tech-insights@0.3.21-next.1
|
||||
- @backstage/plugin-tech-radar@0.6.12-next.1
|
||||
- @backstage/plugin-techdocs@1.9.3-next.1
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
|
||||
- @backstage/plugin-techdocs-react@1.1.15-next.1
|
||||
- @backstage/plugin-todo@0.2.33-next.1
|
||||
- @backstage/plugin-visualizer@0.0.2-next.1
|
||||
- app-next-example-plugin@0.0.5-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/theme@0.5.0
|
||||
- @backstage/plugin-catalog-common@1.0.19
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
- @backstage/plugin-search-common@1.2.9
|
||||
|
||||
## 0.0.5-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -15,7 +15,7 @@ app:
|
||||
- entity-card:catalog/links:
|
||||
config:
|
||||
filter: kind:component has:links
|
||||
|
||||
- entity-card:linguist/languages
|
||||
# Entity page content
|
||||
- entity-content:techdocs
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app-next",
|
||||
"version": "0.0.5-next.0",
|
||||
"version": "0.0.5-next.2",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
@@ -21,6 +21,7 @@
|
||||
"@backstage/plugin-airbrake": "workspace:^",
|
||||
"@backstage/plugin-apache-airflow": "workspace:^",
|
||||
"@backstage/plugin-api-docs": "workspace:^",
|
||||
"@backstage/plugin-app-visualizer": "workspace:^",
|
||||
"@backstage/plugin-azure-devops": "workspace:^",
|
||||
"@backstage/plugin-azure-sites": "workspace:^",
|
||||
"@backstage/plugin-badges": "workspace:^",
|
||||
@@ -74,7 +75,6 @@
|
||||
"@backstage/plugin-techdocs-react": "workspace:^",
|
||||
"@backstage/plugin-todo": "workspace:^",
|
||||
"@backstage/plugin-user-settings": "workspace:^",
|
||||
"@backstage/plugin-visualizer": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@circleci/backstage-plugin": "^0.1.1",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
createExtensionOverrides,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import techdocsPlugin from '@backstage/plugin-techdocs/alpha';
|
||||
import appVisualizerPlugin from '@backstage/plugin-visualizer';
|
||||
import appVisualizerPlugin from '@backstage/plugin-app-visualizer';
|
||||
import { homePage } from './HomePage';
|
||||
import { convertLegacyApp } from '@backstage/core-compat-api';
|
||||
import { FlatRoutes } from '@backstage/core-app-api';
|
||||
@@ -51,6 +51,8 @@ import {
|
||||
import { createSignInPageExtension } from '@backstage/frontend-plugin-api';
|
||||
import { SignInPage } from '@backstage/core-components';
|
||||
|
||||
import linguistPlugin from '@backstage/plugin-linguist/alpha';
|
||||
|
||||
/*
|
||||
|
||||
# Notes
|
||||
@@ -125,6 +127,7 @@ const app = createApp({
|
||||
userSettingsPlugin,
|
||||
homePlugin,
|
||||
appVisualizerPlugin,
|
||||
linguistPlugin,
|
||||
...collectedLegacyPlugins,
|
||||
createExtensionOverrides({
|
||||
extensions: [
|
||||
|
||||
@@ -1,5 +1,145 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.91-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-user-settings@0.8.0-next.2
|
||||
- @backstage/plugin-octopus-deploy@0.2.11-next.2
|
||||
- @backstage/frontend-app-api@0.4.1-next.2
|
||||
- @backstage/plugin-home@0.6.1-next.2
|
||||
- @backstage/plugin-scaffolder-react@1.7.1-next.2
|
||||
- @backstage/plugin-scaffolder@1.17.1-next.2
|
||||
- @backstage/plugin-linguist@0.1.14-next.2
|
||||
- @backstage/plugin-catalog@1.16.1-next.2
|
||||
- @backstage/plugin-catalog-import@0.10.5-next.2
|
||||
- @backstage/plugin-graphiql@0.3.2-next.2
|
||||
- @backstage/plugin-search@1.4.5-next.2
|
||||
- @backstage/plugin-tech-radar@0.6.12-next.2
|
||||
- @backstage/plugin-techdocs@1.9.3-next.2
|
||||
- @backstage/plugin-adr@0.6.12-next.2
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.2
|
||||
- @backstage/plugin-explore@0.4.15-next.2
|
||||
- @backstage/plugin-search-react@1.7.5-next.2
|
||||
- @backstage/plugin-stack-overflow@0.1.24-next.2
|
||||
- @backstage/cli@0.25.1-next.1
|
||||
- @backstage/plugin-pagerduty@0.7.1-next.2
|
||||
- @backstage/plugin-api-docs@0.10.3-next.2
|
||||
- @backstage/plugin-catalog-graph@0.3.3-next.2
|
||||
- @backstage/plugin-org@0.6.19-next.2
|
||||
- @backstage/plugin-airbrake@0.3.29-next.2
|
||||
- @backstage/plugin-azure-devops@0.3.11-next.2
|
||||
- @backstage/plugin-azure-sites@0.1.18-next.2
|
||||
- @backstage/plugin-badges@0.2.53-next.2
|
||||
- @backstage/plugin-cloudbuild@0.3.29-next.2
|
||||
- @backstage/plugin-code-coverage@0.2.22-next.2
|
||||
- @backstage/plugin-cost-insights@0.12.18-next.2
|
||||
- @backstage/plugin-dynatrace@8.0.3-next.2
|
||||
- @backstage/plugin-entity-feedback@0.2.12-next.2
|
||||
- @backstage/plugin-github-actions@0.6.10-next.2
|
||||
- @backstage/plugin-gocd@0.1.35-next.2
|
||||
- @backstage/plugin-jenkins@0.9.4-next.2
|
||||
- @backstage/plugin-kafka@0.3.29-next.2
|
||||
- @backstage/plugin-kubernetes@0.11.4-next.2
|
||||
- @backstage/plugin-kubernetes-cluster@0.0.5-next.2
|
||||
- @backstage/plugin-lighthouse@0.4.14-next.2
|
||||
- @backstage/plugin-newrelic-dashboard@0.3.4-next.2
|
||||
- @backstage/plugin-nomad@0.1.10-next.2
|
||||
- @backstage/plugin-playlist@0.2.3-next.2
|
||||
- @backstage/plugin-puppetdb@0.1.12-next.2
|
||||
- @backstage/plugin-rollbar@0.4.29-next.2
|
||||
- @backstage/plugin-sentry@0.5.14-next.2
|
||||
- @backstage/plugin-tech-insights@0.3.21-next.2
|
||||
- @backstage/plugin-todo@0.2.33-next.2
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
|
||||
- @backstage/integration-react@1.1.23-next.0
|
||||
- @backstage/plugin-apache-airflow@0.2.19-next.1
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
|
||||
- @backstage/plugin-devtools@0.1.8-next.1
|
||||
- @backstage/plugin-gcalendar@0.3.22-next.1
|
||||
- @backstage/plugin-gcp-projects@0.3.45-next.1
|
||||
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
|
||||
- @backstage/plugin-newrelic@0.3.44-next.1
|
||||
- @backstage/plugin-shortcuts@0.3.18-next.1
|
||||
- @backstage/plugin-stackstorm@0.1.10-next.1
|
||||
|
||||
## 0.2.91-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-azure-sites@0.1.18-next.1
|
||||
- @backstage/core-plugin-api@1.8.2-next.0
|
||||
- @backstage/plugin-user-settings@0.8.0-next.1
|
||||
- @backstage/plugin-kubernetes@0.11.4-next.1
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/app-defaults@1.4.7-next.1
|
||||
- @backstage/cli@0.25.1-next.1
|
||||
- @backstage/core-app-api@1.11.3-next.0
|
||||
- @backstage/frontend-app-api@0.4.1-next.1
|
||||
- @backstage/integration-react@1.1.23-next.0
|
||||
- @backstage/plugin-adr@0.6.12-next.1
|
||||
- @backstage/plugin-airbrake@0.3.29-next.1
|
||||
- @backstage/plugin-apache-airflow@0.2.19-next.1
|
||||
- @backstage/plugin-api-docs@0.10.3-next.1
|
||||
- @backstage/plugin-azure-devops@0.3.11-next.1
|
||||
- @backstage/plugin-badges@0.2.53-next.1
|
||||
- @backstage/plugin-catalog@1.16.1-next.1
|
||||
- @backstage/plugin-catalog-graph@0.3.3-next.1
|
||||
- @backstage/plugin-catalog-import@0.10.5-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.1
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1
|
||||
- @backstage/plugin-cloudbuild@0.3.29-next.1
|
||||
- @backstage/plugin-code-coverage@0.2.22-next.1
|
||||
- @backstage/plugin-cost-insights@0.12.18-next.1
|
||||
- @backstage/plugin-devtools@0.1.8-next.1
|
||||
- @backstage/plugin-dynatrace@8.0.3-next.1
|
||||
- @backstage/plugin-entity-feedback@0.2.12-next.1
|
||||
- @backstage/plugin-explore@0.4.15-next.1
|
||||
- @backstage/plugin-gcalendar@0.3.22-next.1
|
||||
- @backstage/plugin-gcp-projects@0.3.45-next.1
|
||||
- @backstage/plugin-github-actions@0.6.10-next.1
|
||||
- @backstage/plugin-gocd@0.1.35-next.1
|
||||
- @backstage/plugin-graphiql@0.3.2-next.1
|
||||
- @backstage/plugin-home@0.6.1-next.1
|
||||
- @backstage/plugin-jenkins@0.9.4-next.1
|
||||
- @backstage/plugin-kafka@0.3.29-next.1
|
||||
- @backstage/plugin-kubernetes-cluster@0.0.5-next.1
|
||||
- @backstage/plugin-lighthouse@0.4.14-next.1
|
||||
- @backstage/plugin-linguist@0.1.14-next.1
|
||||
- @backstage/plugin-microsoft-calendar@0.1.11-next.1
|
||||
- @backstage/plugin-newrelic@0.3.44-next.1
|
||||
- @backstage/plugin-newrelic-dashboard@0.3.4-next.1
|
||||
- @backstage/plugin-nomad@0.1.10-next.1
|
||||
- @backstage/plugin-octopus-deploy@0.2.11-next.1
|
||||
- @backstage/plugin-org@0.6.19-next.1
|
||||
- @backstage/plugin-pagerduty@0.7.1-next.1
|
||||
- @backstage/plugin-permission-react@0.4.19-next.1
|
||||
- @backstage/plugin-playlist@0.2.3-next.1
|
||||
- @backstage/plugin-puppetdb@0.1.12-next.1
|
||||
- @backstage/plugin-rollbar@0.4.29-next.1
|
||||
- @backstage/plugin-scaffolder@1.17.1-next.1
|
||||
- @backstage/plugin-scaffolder-react@1.7.1-next.1
|
||||
- @backstage/plugin-search@1.4.5-next.1
|
||||
- @backstage/plugin-search-react@1.7.5-next.1
|
||||
- @backstage/plugin-sentry@0.5.14-next.1
|
||||
- @backstage/plugin-shortcuts@0.3.18-next.1
|
||||
- @backstage/plugin-stack-overflow@0.1.24-next.1
|
||||
- @backstage/plugin-stackstorm@0.1.10-next.1
|
||||
- @backstage/plugin-tech-insights@0.3.21-next.1
|
||||
- @backstage/plugin-tech-radar@0.6.12-next.1
|
||||
- @backstage/plugin-techdocs@1.9.3-next.1
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1
|
||||
- @backstage/plugin-techdocs-react@1.1.15-next.1
|
||||
- @backstage/plugin-todo@0.2.33-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/theme@0.5.0
|
||||
- @backstage/plugin-catalog-common@1.0.19
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
- @backstage/plugin-search-common@1.2.9
|
||||
|
||||
## 0.2.91-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.91-next.0",
|
||||
"version": "0.2.91-next.2",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.5.10-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 516fd3e: Updated README to reflect release status
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
- @backstage/backend-common@0.20.1-next.2
|
||||
- @backstage/plugin-auth-node@0.4.3-next.2
|
||||
- @backstage/plugin-permission-node@0.7.20-next.2
|
||||
- @backstage/backend-tasks@0.5.14-next.2
|
||||
- @backstage/cli-node@0.2.2-next.0
|
||||
- @backstage/config-loader@1.6.1-next.0
|
||||
|
||||
## 0.5.10-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config-loader@1.6.1-next.0
|
||||
- @backstage/cli-node@0.2.2-next.0
|
||||
- @backstage/backend-common@0.20.1-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/backend-tasks@0.5.14-next.1
|
||||
- @backstage/plugin-auth-node@0.4.3-next.1
|
||||
- @backstage/plugin-permission-node@0.7.20-next.1
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
- @backstage/cli-common@0.1.13
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/types@1.1.1
|
||||
|
||||
## 0.5.10-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
**This package is EXPERIMENTAL, we recommend against using it for production deployments**
|
||||
|
||||
This package provides the core API used by Backstage backend apps.
|
||||
This package provides the framework API used by Backstage backend apps.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.5.10-next.0",
|
||||
"version": "0.5.10-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.20.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
- @backstage/backend-dev-utils@0.1.3-next.0
|
||||
- @backstage/backend-app-api@0.5.10-next.2
|
||||
- @backstage/config-loader@1.6.1-next.0
|
||||
|
||||
## 0.20.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config-loader@1.6.1-next.0
|
||||
- @backstage/backend-app-api@0.5.10-next.1
|
||||
- @backstage/integration@1.8.0
|
||||
- @backstage/integration-aws-node@0.1.8
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/backend-dev-utils@0.1.2
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
- @backstage/cli-common@0.1.13
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/types@1.1.1
|
||||
|
||||
## 0.20.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -417,6 +417,7 @@ export class Git {
|
||||
force?: boolean;
|
||||
}): Promise<PushResult>;
|
||||
readCommit(options: { dir: string; sha: string }): Promise<ReadCommitResult>;
|
||||
remove(options: { dir: string; filepath: string }): Promise<void>;
|
||||
resolveRef(options: { dir: string; ref: string }): Promise<string>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.20.1-next.0",
|
||||
"version": "0.20.1-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -63,6 +63,22 @@ describe('Git', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove', () => {
|
||||
it('should call isomorphic-git remove with the correct arguments', async () => {
|
||||
const git = Git.fromAuth({});
|
||||
const dir = 'mockdirectory';
|
||||
const filepath = 'mockfile/path';
|
||||
|
||||
await git.remove({ dir, filepath });
|
||||
|
||||
expect(isomorphic.remove).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
filepath,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteRemote', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
@@ -300,6 +300,15 @@ export class Git {
|
||||
return git.readCommit({ fs, dir, oid: sha });
|
||||
}
|
||||
|
||||
/** https://isomorphic-git.org/docs/en/remove */
|
||||
async remove(options: { dir: string; filepath: string }): Promise<void> {
|
||||
const { dir, filepath } = options;
|
||||
this.config.logger?.info(
|
||||
`Removing file from git index {dir=${dir},filepath=${filepath}}`,
|
||||
);
|
||||
return git.remove({ fs, dir, filepath });
|
||||
}
|
||||
|
||||
/** https://isomorphic-git.org/docs/en/resolveRef */
|
||||
async resolveRef(options: { dir: string; ref: string }): Promise<string> {
|
||||
const { dir, ref } = options;
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.2.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 516fd3e: Updated README to reflect release status
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
- @backstage/backend-app-api@0.5.10-next.2
|
||||
- @backstage/backend-common@0.20.1-next.2
|
||||
|
||||
## 0.2.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.5.10-next.1
|
||||
- @backstage/backend-common@0.20.1-next.1
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
|
||||
## 0.2.9-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
**This package is EXPERIMENTAL, we recommend against using it for production deployments**
|
||||
|
||||
This package provides the default implementations and setup for a standard Backstage backend app.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.2.9-next.0",
|
||||
"version": "0.2.9-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/backend-dev-utils
|
||||
|
||||
## 0.1.3-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 516fd3e: Updated README to reflect release status
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# @backstage/backend-dev-utils
|
||||
|
||||
**This package is EXPERIMENTAL, but we encourage use of it to add support for the new backend system in your own plugins**
|
||||
|
||||
This package helps set up local development environments for Backstage backend packages.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-dev-utils",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,86 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.19-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-sonarqube-backend@0.2.11-next.2
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
- @backstage/backend-defaults@0.2.9-next.2
|
||||
- @backstage/plugin-adr-backend@0.4.6-next.2
|
||||
- @backstage/plugin-app-backend@0.3.57-next.2
|
||||
- @backstage/plugin-auth-node@0.4.3-next.2
|
||||
- @backstage/plugin-azure-devops-backend@0.5.1-next.2
|
||||
- @backstage/plugin-badges-backend@0.3.6-next.2
|
||||
- @backstage/plugin-catalog-backend@1.16.1-next.2
|
||||
- @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.2
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.2
|
||||
- @backstage/plugin-devtools-backend@0.2.6-next.2
|
||||
- @backstage/plugin-entity-feedback-backend@0.2.6-next.2
|
||||
- @backstage/plugin-jenkins-backend@0.3.3-next.2
|
||||
- @backstage/plugin-kubernetes-backend@0.14.1-next.2
|
||||
- @backstage/plugin-lighthouse-backend@0.4.1-next.2
|
||||
- @backstage/plugin-linguist-backend@0.5.6-next.2
|
||||
- @backstage/plugin-nomad-backend@0.1.11-next.2
|
||||
- @backstage/plugin-permission-backend@0.5.32-next.2
|
||||
- @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.2
|
||||
- @backstage/plugin-permission-node@0.7.20-next.2
|
||||
- @backstage/plugin-playlist-backend@0.3.13-next.2
|
||||
- @backstage/plugin-proxy-backend@0.4.7-next.2
|
||||
- @backstage/plugin-scaffolder-backend@1.19.3-next.2
|
||||
- @backstage/plugin-search-backend@1.4.9-next.2
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.13-next.2
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.13-next.2
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2
|
||||
- @backstage/plugin-search-backend-node@1.2.13-next.2
|
||||
- @backstage/plugin-techdocs-backend@1.9.2-next.2
|
||||
- @backstage/plugin-todo-backend@0.3.7-next.2
|
||||
- @backstage/backend-tasks@0.5.14-next.2
|
||||
- @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.2
|
||||
|
||||
## 0.0.19-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-app-backend@0.3.57-next.1
|
||||
- @backstage/plugin-devtools-backend@0.2.6-next.1
|
||||
- @backstage/plugin-proxy-backend@0.4.7-next.1
|
||||
- @backstage/backend-defaults@0.2.9-next.1
|
||||
- @backstage/plugin-kubernetes-backend@0.14.1-next.1
|
||||
- @backstage/backend-tasks@0.5.14-next.1
|
||||
- @backstage/plugin-adr-backend@0.4.6-next.1
|
||||
- @backstage/plugin-auth-node@0.4.3-next.1
|
||||
- @backstage/plugin-azure-devops-backend@0.5.1-next.1
|
||||
- @backstage/plugin-badges-backend@0.3.6-next.1
|
||||
- @backstage/plugin-catalog-backend@1.16.1-next.1
|
||||
- @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.1
|
||||
- @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.1
|
||||
- @backstage/plugin-entity-feedback-backend@0.2.6-next.1
|
||||
- @backstage/plugin-jenkins-backend@0.3.3-next.1
|
||||
- @backstage/plugin-lighthouse-backend@0.4.1-next.1
|
||||
- @backstage/plugin-linguist-backend@0.5.6-next.1
|
||||
- @backstage/plugin-nomad-backend@0.1.11-next.1
|
||||
- @backstage/plugin-permission-backend@0.5.32-next.1
|
||||
- @backstage/plugin-permission-node@0.7.20-next.1
|
||||
- @backstage/plugin-playlist-backend@0.3.13-next.1
|
||||
- @backstage/plugin-scaffolder-backend@1.19.3-next.1
|
||||
- @backstage/plugin-search-backend@1.4.9-next.1
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.13-next.1
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.13-next.1
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1
|
||||
- @backstage/plugin-search-backend-node@1.2.13-next.1
|
||||
- @backstage/plugin-sonarqube-backend@0.2.11-next.1
|
||||
- @backstage/plugin-techdocs-backend@1.9.2-next.1
|
||||
- @backstage/plugin-todo-backend@0.3.7-next.1
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.1
|
||||
- @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.1
|
||||
- @backstage/plugin-permission-common@0.7.11
|
||||
|
||||
## 0.0.19-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# example-backend-next
|
||||
|
||||
This is an example backend for the new **EXPERIMENTAL** Backstage backend system.
|
||||
This is an example backend for [the new Backstage backend system](https://backstage.io/docs/backend-system/).
|
||||
|
||||
Do not use this in your own projects.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.19-next.0",
|
||||
"version": "0.0.19-next.2",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @backstage/backend-openapi-utils
|
||||
|
||||
## 0.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
|
||||
## 0.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-openapi-utils",
|
||||
"description": "OpenAPI typescript support.",
|
||||
"version": "0.1.2-next.0",
|
||||
"version": "0.1.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.6.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 516fd3e: Updated README to reflect release status
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-auth-node@0.4.3-next.2
|
||||
- @backstage/backend-tasks@0.5.14-next.2
|
||||
|
||||
## 0.6.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/backend-tasks@0.5.14-next.1
|
||||
- @backstage/plugin-auth-node@0.4.3-next.1
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-permission-common@0.7.11
|
||||
|
||||
## 0.6.9-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
**This package is EXPERIMENTAL, but we encourage use of it to add support for the new backend system in your own plugins**
|
||||
|
||||
This package provides the core API used by Backstage backend plugins and modules.
|
||||
This package provides the framework API used by Backstage backend plugins and modules.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user