Merge remote-tracking branch 'upstream/master' into improvemsgraphperf
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-sonarqube': patch
|
||||
---
|
||||
|
||||
Additional export added in order to bind SonarQubeClient to its apiref
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
`scaffolder/next`: bump `react-jsonschema-form` libraries to `v5-stable`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
The `backstage-cli repo test` command now sets a default Jest `--workerIdleMemoryLimit` of 1GB. If needed to ensure that tests are not run in band, `--maxWorkers=2` is set as well. This is the recommended workaround for dealing with Jest workers leaking memory and eventually hitting the heap limit.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': minor
|
||||
---
|
||||
|
||||
Update DocsTable and EntityListDocsTable to accept overrides for Material Table options.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Added a check to ensure that Yarn v1 is used when creating new projects.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
The previous migration that adds the `search.original_value` column may leave some of the entities not updated. Add a migration script to trigger a reprocessing of the entities.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend': patch
|
||||
'@backstage/plugin-tech-insights-common': patch
|
||||
'@backstage/plugin-tech-insights-node': minor
|
||||
'@backstage/plugin-tech-insights': patch
|
||||
---
|
||||
|
||||
TechInsightsApi interface now has getFactSchemas() method.
|
||||
TechInsightsClient now implements method getFactSchemas().
|
||||
|
||||
**BREAKING** FactSchema type moved from @backstage/plugin-tech-insights-node into @backstage/plugin-tech-insights-common
|
||||
|
||||
These changes are **required** if you were importing this type directly.
|
||||
|
||||
```diff
|
||||
- import { FactSchema } from '@backstage/plugin-tech-insights-node';
|
||||
+ import { FactSchema } from '@backstage/plugin-tech-insights-common';
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Fix MS Graph provider to use target URL for fetching access token
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search': minor
|
||||
---
|
||||
|
||||
Update `SearchModal` component to use `SearchResult` extensions.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-azure-devops-backend': patch
|
||||
---
|
||||
|
||||
Fixed a bug where the azure devops host in URLs on the readme card was being URL encoded, breaking hosts with ports.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-module-addons-contrib': patch
|
||||
'@backstage/plugin-techdocs-addons-test-utils': patch
|
||||
'@backstage/plugin-apollo-explorer': patch
|
||||
'@backstage/plugin-cicd-statistics': patch
|
||||
'@backstage/plugin-codescene': patch
|
||||
'@backstage/plugin-dynatrace': patch
|
||||
'@backstage/plugin-org-react': patch
|
||||
'@backstage/plugin-playlist': patch
|
||||
---
|
||||
|
||||
Depend on `@material-ui/core` version `^4.12.2` like all other in-repo packages
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Add support for filtering out forks
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-sentry': patch
|
||||
---
|
||||
|
||||
Fix broken module exports and dependencies to match a backend module, rather than a frontend plugin.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Fixed regression that caused the `WelcomeTitle` to not be the right size when passed to the `title` property of the `<Header>` component. A Storybook entry was also added for the `WelcomeTitle`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': minor
|
||||
---
|
||||
|
||||
Added Markdown support in the `AboutCard` description section
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Switched the order of reprocessing statements retroactively in migrations. This only improves the experience for those who at a later time perform a large upgrade of an old Backstage installation.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Update `SearchPage` template to use `SearchResult` extensions.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
Fixed an issue where an explicit port the frontend base URL could break the app.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
remove unused plugin-stack-overflow dependency
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-azure': patch
|
||||
---
|
||||
|
||||
This will add the ability to use Azure DevOps with multi project with a single value which is a new feature as previously this had to be done manually for each project that you wanted to add.
|
||||
|
||||
Right now you would have to fill in multiple values in the config to use multiple projects:
|
||||
|
||||
```
|
||||
yourFirstProviderId: # identifies your dataset / provider independent of config changes
|
||||
organization: myorg
|
||||
project: 'firstProject' # this will match the firstProject project
|
||||
repository: '*' # this will match all repos
|
||||
path: /catalog-info.yaml
|
||||
yourSecondProviderId: # identifies your dataset / provider independent of config changes
|
||||
organization: myorg
|
||||
project: 'secondProject' # this will match the secondProject project
|
||||
repository: '*' # this will match all repos
|
||||
path: /catalog-info.yaml
|
||||
```
|
||||
|
||||
With this change you can actually have all projects available where your PAT determines which you have access to, so that includes multiple projects:
|
||||
|
||||
```
|
||||
yourFirstProviderId: # identifies your dataset / provider independent of config changes
|
||||
organization: myorg
|
||||
project: '*' # this will match all projects where your PAT has access to
|
||||
repository: '*' # this will match all repos
|
||||
path: /catalog-info.yaml
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': minor
|
||||
---
|
||||
|
||||
The `CatalogSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-incremental-ingestion': minor
|
||||
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
|
||||
---
|
||||
|
||||
Return EventSubscriber from addIncrementalEntityProvider to hook up to EventsBackend
|
||||
Return `EventSubscriber` from `addIncrementalEntityProvider` to hook up to `EventsBackend`
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
The Button component has been deprecated in favor of the LinkButton component
|
||||
@@ -198,36 +198,79 @@
|
||||
"@backstage/plugin-scaffolder-node": "0.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-foxes-provide",
|
||||
"brave-cougars-burn",
|
||||
"bright-eagles-love",
|
||||
"brown-islands-own",
|
||||
"calm-avocados-exercise",
|
||||
"chatty-owls-care",
|
||||
"clean-queens-judge",
|
||||
"cold-cycles-switch",
|
||||
"create-app-1674561612",
|
||||
"cuddly-boxes-agree",
|
||||
"cyan-deers-walk",
|
||||
"dry-donkeys-cheer",
|
||||
"dull-gorillas-sing",
|
||||
"eight-falcons-explode",
|
||||
"eight-hotels-sparkle",
|
||||
"flat-cups-itch",
|
||||
"four-candles-add",
|
||||
"four-rivers-enjoy",
|
||||
"friendly-scissors-shop",
|
||||
"gold-bulldogs-talk",
|
||||
"gold-lemons-eat",
|
||||
"gold-masks-sleep",
|
||||
"grumpy-bottles-stare",
|
||||
"happy-cows-moo",
|
||||
"hip-pugs-teach",
|
||||
"hot-lions-cover",
|
||||
"hungry-news-fix",
|
||||
"itchy-goats-melt",
|
||||
"khaki-toes-care",
|
||||
"late-rice-crash",
|
||||
"lazy-badgers-rule",
|
||||
"lazy-badgers-try",
|
||||
"lemon-tables-train",
|
||||
"lovely-ladybugs-taste",
|
||||
"many-nails-joke",
|
||||
"modern-cats-worry",
|
||||
"nasty-beans-accept",
|
||||
"neat-zebras-run",
|
||||
"nervous-apricots-whisper",
|
||||
"nervous-mangos-rhyme",
|
||||
"nine-glasses-invent",
|
||||
"nine-guests-compete",
|
||||
"ninety-hats-serve",
|
||||
"old-knives-wonder",
|
||||
"perfect-cheetahs-serve",
|
||||
"pink-falcons-serve",
|
||||
"poor-moons-confess",
|
||||
"popular-dancers-join",
|
||||
"pretty-ladybugs-taste",
|
||||
"purple-feet-smile",
|
||||
"quick-ladybugs-reply",
|
||||
"rare-melons-battle",
|
||||
"renovate-0b349f9",
|
||||
"renovate-0c3644c",
|
||||
"rich-snakes-rest",
|
||||
"rotten-mayflies-love",
|
||||
"sharp-lobsters-build",
|
||||
"shiny-years-tap",
|
||||
"shy-steaks-invite",
|
||||
"silly-turkeys-hang",
|
||||
"smart-dingos-raise",
|
||||
"soft-boxes-buy",
|
||||
"soft-snails-notice",
|
||||
"spotty-coats-clean",
|
||||
"stale-dots-smile",
|
||||
"stupid-ladybugs-brake",
|
||||
"swift-fishes-smash",
|
||||
"tall-years-relate",
|
||||
"thick-clocks-pump",
|
||||
"twenty-islands-wonder",
|
||||
"twenty-parents-relate",
|
||||
"two-melons-lie",
|
||||
"witty-moose-itch",
|
||||
"young-singers-learn"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Adds new type, TableOptions, extending Material Table Options.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Allow to set additional links to the entry description.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Updated dependency `esbuild` to `^0.17.0`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-explore': minor
|
||||
---
|
||||
|
||||
The `ToolSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': patch
|
||||
---
|
||||
|
||||
The `register` methods passed to `createBackendPlugin` and `createBackendModule`
|
||||
now have dedicated `BackendPluginRegistrationPoints` and
|
||||
`BackendModuleRegistrationPoints` arguments, respectively. This lets us make it
|
||||
clear on a type level that it's not possible to pass in extension points as
|
||||
dependencies to plugins (should only ever be done for modules). This has no
|
||||
practical effect on code that was already well behaved.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-bitbucket': patch
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
'@backstage/plugin-catalog-backend-module-gitlab': patch
|
||||
'@backstage/plugin-catalog-backend-module-azure': patch
|
||||
'@backstage/plugin-azure-devops-backend': patch
|
||||
'@backstage/plugin-git-release-manager': patch
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/plugin-playlist-backend': patch
|
||||
'@backstage/plugin-apache-airflow': patch
|
||||
'@backstage/plugin-circleci': patch
|
||||
'@backstage/plugin-bitrise': patch
|
||||
'@backstage/plugin-sentry': patch
|
||||
---
|
||||
|
||||
Internal refactor to not use deprecated `substr`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Implement Group and User Catalog Provider
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Prefer schema ordering of template properties during review content generation.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-search-react': minor
|
||||
---
|
||||
|
||||
- Create the search results extensions, for more details see the documentation [here](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions);
|
||||
- Update the `SearchResult`, `SearchResultList` and `SearchResultGroup` components to use extensions and default their props to optionally accept a query, when the query is not passed, the component tries to get it from the search context.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-airbrake': patch
|
||||
---
|
||||
|
||||
Adds a boolean helper function to airbrake plugin for use on the EntityPage to show/hide airbrake tab depending on whether the entity's catalog-info.yml has an airbrake id set in the metadata
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Fixed bug in review step refactor that caused schema-based display settings for individual property values to be discarded.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': minor
|
||||
---
|
||||
|
||||
Aligned buttons on "Unregister entity" dialog to keep them on the same line
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Switch to inline source maps for test transpilation, simplifying editor setups.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': minor
|
||||
---
|
||||
|
||||
The `TechDocsSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
|
||||
@@ -1,6 +1,6 @@
|
||||
name: '🐛 Bug Report'
|
||||
description: 'Submit a bug report to help us improve'
|
||||
title: '🐛 Bug Report: '
|
||||
title: '🐛 Bug Report: <title>'
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 🚀 Feature
|
||||
description: 'Submit a proposal for a new feature'
|
||||
title: '🚀 Feature: '
|
||||
title: '🚀 Feature: <title>'
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 🔌 Plugin
|
||||
description: 'Submit a proposal for a new Plugin'
|
||||
title: '🔌 Plugin: '
|
||||
title: '🔌 Plugin: <title>'
|
||||
labels: [plugin]
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 💬 RFC
|
||||
description: 'Request For Comments (RFC) from the community'
|
||||
title: '💬 RFC: '
|
||||
title: '💬 RFC: <title>'
|
||||
labels: [rfc]
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 🦄 UX Component
|
||||
description: 'For designers to request UX components to be added to the Backstage Storybook'
|
||||
title: '🦄 UX Component: '
|
||||
title: '🦄 UX Component: <title>'
|
||||
labels: [design]
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -53,10 +53,6 @@ jobs:
|
||||
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
# TODO(Rugvip): Remove the create-app dispatch once we've been on the release version for a while
|
||||
script: |
|
||||
const releaseVersion = require('./backstage/package.json').version;
|
||||
if(releaseVersion.includes('next')) {
|
||||
return;
|
||||
}
|
||||
console.log('Dispatching upgrade helper sync');
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: 'backstage',
|
||||
@@ -65,6 +61,6 @@ jobs:
|
||||
ref: 'master',
|
||||
inputs: {
|
||||
version: require('./backstage/packages/create-app/package.json').version,
|
||||
releaseVersion
|
||||
releaseVersion: require('./backstage/package.json').version
|
||||
},
|
||||
});
|
||||
|
||||
@@ -89,16 +89,11 @@ jobs:
|
||||
name: preview-spec
|
||||
path: docker-compose.rendered.yml
|
||||
retention-days: 2
|
||||
- name: Serialize PR Event to File
|
||||
run: |
|
||||
cat << EOF > event.json
|
||||
${{ toJSON(github.event) }}
|
||||
EOF
|
||||
- name: Upload PR Event as Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: event.json
|
||||
path: ${{ github.event_path }}
|
||||
retention-days: 2
|
||||
|
||||
delete-preview:
|
||||
@@ -107,14 +102,9 @@ jobs:
|
||||
if: ${{ github.event.action == 'closed' }}
|
||||
steps:
|
||||
# If this PR is closing, we will not render a compose file nor pass it to the next workflow.
|
||||
- name: Serialize PR Event to File
|
||||
run: |
|
||||
cat << EOF > event.json
|
||||
${{ toJSON(github.event) }}
|
||||
EOF
|
||||
- name: Upload PR Event as Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: event.json
|
||||
path: ${{ github.event_path }}
|
||||
retention-days: 2
|
||||
|
||||
@@ -11,6 +11,7 @@ jobs:
|
||||
cache-compose-file:
|
||||
name: Cache Compose File
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
outputs:
|
||||
compose-file-cache-key: ${{ env.COMPOSE_FILE_HASH }}
|
||||
pr-number: ${{ env.PR_NUMBER }}
|
||||
@@ -47,7 +48,7 @@ jobs:
|
||||
run: |
|
||||
echo 'EVENT_JSON<<EOF' >> $GITHUB_ENV
|
||||
cat event.json >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
echo -e '\nEOF' >> $GITHUB_ENV
|
||||
|
||||
- name: Hash Rendered Compose File
|
||||
id: hash
|
||||
@@ -77,6 +78,7 @@ jobs:
|
||||
name: Use Remote Workflow to Preview on Uffizzi
|
||||
needs:
|
||||
- cache-compose-file
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2
|
||||
with:
|
||||
# If this workflow was triggered by a PR close event, cache-key will be an empty string
|
||||
|
||||
@@ -94,6 +94,13 @@ This section describes guidelines for designing public APIs. It can also be appl
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// In order to make a private constructor available for testing you can use a
|
||||
// static factory marked as `@internal`, which will not show up in the public API.
|
||||
/** @internal */
|
||||
static forTesting(internalOptions?: { ... }) {
|
||||
return new DefaultImageLoader(internalOptions);
|
||||
}
|
||||
|
||||
private constructor(/* ... */) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@@ -1,32 +1,28 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="522px" height="282px" viewBox="-0.5 -0.5 522 282" content="<mxfile scale="1.5" border="20"><diagram id="gKBvn7eBFHudv9VMIRD-" name="Page-1">3VhBc6IwGP01XDtAAPW4tbZ76Ywz7sx2jylEyBgTJwTF/fUbSJBErKtsq654kPfyhYT3Mg+CA8bL8oXDVfbKEkQc301KBzw5vu95wJd/FbNVTDgaKCLlONFFLTHDv5EmXc0WOEG5VSgYIwKvbDJmlKJYWBzknG3ssjkj9qgrmKIOMYsh6bI/cSIyxYLAbfnvCKdZM/JQN7zDeJFyVlA9nOODeX2o5iVsLqXr8wwmbGNQYOKAMWdMqLNlOUakkrZRTfV7/qB1N22OqDilg3YlF9vmzlEihdCQMir/HjOxJBJ58hTR5Fslr4TvhMWLHxmmin7GxCjSjgYS5QJyYeBaHVSN70rUnXBjN+Qp0lSgqGpqRo2+oxfElkjwrSzgiECB17aHUC+FdFe36zplWI7qu3rZhtqUrQ2bC+Ss4DHSfVpN5YkxiZaqlT6s+vBc1Uss3irBHoaDUONfRttTqdWswdYAU8SxnBjiDXcx/5RaivK7lkaXsRSMbE8HX+apvsc1JIWe7KPMAillx2tbwE2GBZqtYK3VRqapbf1c2jJmhPG6L5hE1a92hbMFMlqi+qh6MCoMXh3HnFojLlB51IWm1RazgRsjIZtgy4x0DNyPbbMUPyIv6Mg7Q3yNY/mQuCN9weHVagg8/CJ9Rz0jyTPiyH0IjwfSVcIn6IZP+Nnhc6rKnt87+a3gd/+is5zWmwkMdyrYdqvRzfkDruVP0EmZKSlSTO8qZPZCHFwuZMKOvJNSIJpjRiVdP4XvSmlwPakbl89PmpsP9OiWAh30DnS/R6B7/0OgH/DnaoEedRLnlSUFuau3xv1960Vj5uz3xs9ekgnMsxp4GkyhkPtdWjO+6+003lt8fTat4B9X7eE9qheNHkLLwRO/PHSutL8S9ne76l567HYlbL9JqfL2ux+Y/AE=</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="642px" height="327px" viewBox="-0.5 -0.5 642 327" content="<mxfile scale="1.5" border="20"><diagram id="gKBvn7eBFHudv9VMIRD-" name="Page-1">3VnbTuMwEP2aPFLl1tsjlMLuw0pI3dXCo0ncxMK1K8dtU75+7dhJnBhKFMJlGySUGV/nnDNjE5xgsclvGdimv2gMseO7ce4E147vz1xX/JaOo3JMZ9qRMBQrl1c7VugZamfZbYdimDU6ckoxR9umM6KEwIg3fIAxemh2W1PcXHULEmg5VhHAtvcvinmqvEHo1v4fECVpuXIZ3iOInhJGd0Qv5/jBunhU8waUU+n+WQpiejBcwdIJFoxSrt42+QJiiWyJmhp380prtW0GCe8ywFcD9gDvdORXIgJI4kzvjx9LSIqooBznOsHVIUUcrrYgkq0HoQHhS/kGC8sTr2uE8YJiyoqxwXIif4Q/44w+QaNlUjxyBCXc8KtH+O2IdJB7yDjMDZeO8BbSDeTsKLro1otAo63FeFGif6ipDUvFpgatJd1Aqymppq4hFS8a1ZcRDiyEV5DtUQTPCWGvhfDUBnj2QfjOLXzvGN2L6mHBC2OR4toklMAmnjBH/N54f5A0jMbaus41K4VxLA0SX8piI8xHTKOn3ykiyn2DcDUxKetbWNADGDfsJueSIt04P8VMRncs0mGFujwClkDda6xcMuCT7DGIAUf7Zs17iQw99I4isZG6C12vM7Fmm61qhU4EenYN+pP1Zc8dTccmgW/QJzZ5bxoG6dKshxXWh9EuEw2Jw+cSo0TMdL1BcYyLCClDz0IToMr6YQQSdBSITm935Lr+TI35FpoJ7aTHuwSRc6qp7VOrqrGfUFTHFr7LnEOSIUqEu6D0nKBuH1+fCXV54zWwXgDZo1/9+99Or8knnF6dqbDvau85ifweJ5H3xSfRQBR2PV8Gp3BiMSj+NN3hs7ps+/Ovq1bVbmuAfxIhqf4Fa+TO50aeeCM37Hhpq7PjwWz79pc2Gc4dZEiAD5merFOi+XaihUMnWudbW90nb8qrVGVbbioSPejEPF57Irc1kYrfmqjHNfKFzx891XwWolQBtLLRP52NA2p58n20HLQuhH217L+REwNK2b679PwOckZSNi9g3kkdxyBLi5W9dwh48FvPOwTcKqKBO5rOjWc87ifo9rzDKVqY9Wdv1b3+z0Kw/Ac=</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<path d="M 79.5 79.5 L 79.5 190.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 79.5 197.82 L 77 190.32 L 82 190.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 439.5 79.5 L 439.5 190.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 439.5 197.82 L 437 190.32 L 442 190.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="19.5" y="19.5" width="480" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="19.5" y="19.5" width="600" height="60" fill="#e6e6e6" 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: 318px; height: 1px; padding-top: 33px; margin-left: 14px;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 33px; margin-left: 14px;">
|
||||
<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
|
||||
Backends
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="173" y="37" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Backend
|
||||
<text x="213" y="37" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Backends
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="199.5" y="109.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="259.5" y="154.5" width="120" height="60" fill="#e6e6e6" 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: 93px; margin-left: 134px;">
|
||||
<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: 123px; 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;">
|
||||
Services
|
||||
@@ -34,20 +30,52 @@
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="173" y="97" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
<text x="213" y="127" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Services
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 139.5 229.5 L 190.32 229.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 197.82 229.5 L 190.32 232 L 190.32 227 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 109.5 199.5 L 191.86 144.59" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 198.1 140.43 L 193.25 146.67 L 190.48 142.51 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="19.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<path d="M 139.5 274.5 L 250.32 274.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 257.82 274.5 L 250.32 277 L 250.32 272 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 78px; height: 1px; padding-top: 153px; margin-left: 14px;">
|
||||
<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: 183px; margin-left: 133px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Provide
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="133" y="186" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Provide
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 109.5 244.5 L 250.98 187.91" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 257.94 185.12 L 251.91 190.23 L 250.05 185.59 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 143px; margin-left: 123px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Use
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="123" y="146" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Use
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="19.5" y="244.5" width="120" height="60" fill="#e6e6e6" 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: 183px; margin-left: 14px;">
|
||||
<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;">
|
||||
Plugins
|
||||
@@ -55,16 +83,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="53" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
<text x="53" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Plugins
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="199.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<rect x="259.5" y="244.5" width="120" height="60" fill="#e6e6e6" 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: 153px; margin-left: 134px;">
|
||||
<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: 183px; 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;">
|
||||
Extension Points
|
||||
@@ -72,20 +100,52 @@
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="173" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
<text x="213" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Extension Poi...
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 379.5 229.5 L 328.68 229.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 321.18 229.5 L 328.68 227 L 328.68 232 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 409.5 199.5 L 327.14 144.59" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 320.9 140.43 L 328.52 142.51 L 325.75 146.67 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="379.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
<path d="M 499.5 274.5 L 388.68 274.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 381.18 274.5 L 388.68 272 L 388.68 277 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 78px; height: 1px; padding-top: 153px; margin-left: 254px;">
|
||||
<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: 183px; margin-left: 293px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Call
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="293" y="186" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Call
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 529.5 244.5 L 388.02 187.91" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 381.06 185.12 L 388.95 185.59 L 387.09 190.23 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 143px; margin-left: 303px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Use
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="303" y="146" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Use
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="499.5" y="244.5" width="120" height="60" fill="#e6e6e6" 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: 183px; margin-left: 334px;">
|
||||
<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;">
|
||||
Modules
|
||||
@@ -93,19 +153,71 @@
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="293" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
<text x="373" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||
Modules
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 259.5 79.5 L 259.5 100.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="1.5 1.5" pointer-events="stroke"/>
|
||||
<path d="M 259.5 107.82 L 257 100.32 L 262 100.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 78.9 81.9 L 79.47 235.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 79.49 242.82 L 76.97 235.33 L 81.97 235.31 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 109px; margin-left: 53px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Install
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="53" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Install
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 559.5 80.7 L 559.5 235.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 559.5 242.82 L 557 235.32 L 562 235.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 108px; margin-left: 373px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Install
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="373" y="111" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Install
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 319.5 79.5 L 319.5 145.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="stroke"/>
|
||||
<path d="M 319.5 152.82 L 317 145.32 L 322 145.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" 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: 78px; margin-left: 213px;">
|
||||
<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: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
|
||||
Provide
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="213" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Provide
|
||||
</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%">
|
||||
Viewer does not support full SVG 1.1
|
||||
Text is not SVG - cannot display
|
||||
</text>
|
||||
</a>
|
||||
</switch>
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 19 KiB |
@@ -6,16 +6,14 @@ sidebar_label: System Architecture
|
||||
description: The structure and architecture of the new Backend System and its component parts
|
||||
---
|
||||
|
||||
# Overview
|
||||
## Building Blocks
|
||||
|
||||
This section introduces the high-level building blocks upon which this new
|
||||
system is built. These are all concepts that exist in our current system in one
|
||||
way or another, but they have all been lifted up to be first class concerns in
|
||||
the new system.
|
||||
|
||||
## Building Blocks
|
||||
|
||||
This section introduces the high-level building blocks upon which this new system is built. Regardless of whether you are setting up your own backstage instance, developing plugins, or extending plugins with new features, it is important to understand these concepts.
|
||||
the new system. Regardless of whether you are setting up your own backstage
|
||||
instance, developing plugins, or extending plugins with new features, it is
|
||||
important to understand these concepts.
|
||||
|
||||
The diagram below provides an overview of the different building blocks, and the other blocks that each of them interact with.
|
||||
|
||||
@@ -37,7 +35,7 @@ Plugins provide the actual features, just like in our existing system. They oper
|
||||
|
||||
Services provide utilities to help make it simpler to implement plugins, so that each plugin doesn't need to implement everything from scratch. There are both many built-in services, like the ones for logging, database access, and reading configuration, but you can also import third-party services, or create your own.
|
||||
|
||||
Services are also a customization point for individual backend installations. You can both override services with your own implementations, as well as make smaller customizations to existing services.
|
||||
Services are also a customization point for individual backend installations. You can override services with your own implementations, as well as make smaller customizations to existing services.
|
||||
|
||||
### Extension Points
|
||||
|
||||
@@ -45,7 +43,7 @@ Many plugins have ways in which you can extend them, for example entity provider
|
||||
|
||||
Extension Points look a little bit like services, since you depended on them just like you would a service. A key difference is that extension points are registered and provided by plugins themselves, based on what customizations each individual plugin wants to expose.
|
||||
|
||||
Extension Points are also exported separately from the plugin instance itself, and a single plugin can also expose multiple different extension points at once. This makes it easier to evolve and deprecated individual Extension Points over time, rather than dealing with a single large API surface.
|
||||
Extension Points are also exported separately from the plugin instance itself, and a single plugin can also expose multiple different extension points at once. This makes it easier to evolve and deprecate individual Extension Points over time, rather than dealing with a single large API surface.
|
||||
|
||||
### Modules
|
||||
|
||||
@@ -53,22 +51,20 @@ Modules use the plugin Extension Points to add new features for plugins. They mi
|
||||
|
||||
Each module may only extend a single plugin, and the module must be deployed together with that plugin in the same backend instance. Modules may however only communicate with their plugin through its registered extension points.
|
||||
|
||||
Just like plugins, modules also have access to services and can depend on their own service implementations. They will however share services with the plugin that they extend, there are no module-specific service implementations.
|
||||
Just like plugins, modules also have access to services and can depend on their own service implementations. They will however share services with the plugin that they extend - there are no module-specific service implementations.
|
||||
|
||||
## Package structure
|
||||
|
||||
A detailed explanation of the package architecture can be found in the
|
||||
[Backstage Architecture
|
||||
Overview](../../overview/architecture-overview.md#package-architecture). The
|
||||
most important packages to consider for this system are `backend`,
|
||||
`plugin-<pluginId>-backend`, `plugin-<pluginId>-node`, and
|
||||
`plugin-<pluginId>-backend-module-<moduleId>`.
|
||||
most important packages to consider for this system are the following:
|
||||
|
||||
- `plugin-<pluginId>-backend` houses the implementation of the backend plugins
|
||||
themselves.
|
||||
- `plugin-<pluginId>-node` houses the extension points and any other utilities
|
||||
- `plugin-<pluginId>-node` houses the backend plugin's extension points and any other utilities
|
||||
that modules or other plugins might need.
|
||||
- `plugin-<pluginId>-backend-module-<moduleId>` houses the modules that extend
|
||||
the plugins via the extension points.
|
||||
the plugin via its extension points.
|
||||
- `backend` is the backend itself that wires everything together to something
|
||||
that you can deploy.
|
||||
|
||||
@@ -1,103 +1,227 @@
|
||||
---
|
||||
id: services
|
||||
title: Backend Service APIs
|
||||
sidebar_label: Service APIs
|
||||
title: Backend Services
|
||||
sidebar_label: Services
|
||||
# prettier-ignore
|
||||
description: Service APIs for backend plugins
|
||||
description: Services for backend plugins
|
||||
---
|
||||
|
||||
## Backend Services
|
||||
Backend services provide shared functionality available to all backend plugins and modules. They are made available through service references that embed a type that represents the service interface, similar to how [Utility APIs](../../api/utility-apis.md) work in the Backstage frontend system. To use a service in your plugin or module you request an implementation of that service using the service reference.
|
||||
|
||||
The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, databases and more.
|
||||
Service dependencies are declared using their `ServiceRef`s in the `deps` section of the plugin or module, and the implementations are then forwarded to the `init` method of the plugin or module.
|
||||
The system surrounding services exists to provide a level of indirection between the service interfaces and their implementation. It is an implementation of dependency injection, where each backend instance is the dependency injection container. The implementation for each service is provided by a service factory, which encapsulates the logic for how each service instance is created.
|
||||
|
||||
### Service References
|
||||
## Service Interfaces
|
||||
|
||||
A `ServiceRef` is a named reference to an interface which are later used to resolve the concrete service implementation. Conceptually this is very similar to `ApiRef`s in the frontend.
|
||||
Services is what provides common utilities that previously resided in the `PluginEnvironment` such as Config, Logging and Database.
|
||||
Service interfaces can be any TypeScript type, but it is best to make it an object interface with a number of methods. General guidelines for interface design apply: keep them simple and lean, with few but powerful methods. Take care to avoid locking down the ways in which individual methods can evolve. Often you want to stick to a method with an options object as its only parameter, and return a result object. If there is any reason for uncertainty about whether the method should be async or not, always make it async. For example, a minimal interface should often use the following pattern:
|
||||
|
||||
On startup the backend will make sure that the services are initialized before being passed to the plugin/module that depend on them.
|
||||
ServiceRefs contain a scope which is used to determine if the serviceFactory creating the service will create a new instance scoped per plugin/module or if it will be shared. `plugin` scoped services will be created once per plugin/module and `root` scoped services will be created once per backend instance.
|
||||
```ts
|
||||
export interface FooService {
|
||||
foo(options: FooOptions): Promise<FooResult>;
|
||||
}
|
||||
```
|
||||
|
||||
#### Defining a Service
|
||||
## Service References
|
||||
|
||||
Once you have defined a service interface, you need to create a service reference using the `createServiceRef` function. This will create a `ServiceRef` instance, which is a reference that you export in order to allow users to interact with your service. Conceptually this is very similar to `ApiRef`s in the frontend system. For example:
|
||||
|
||||
```ts
|
||||
import { createServiceRef } from '@backstage/backend-plugin-api';
|
||||
|
||||
export interface FooService {
|
||||
foo(options: FooOptions): Promise<FooResult>;
|
||||
}
|
||||
|
||||
export const fooServiceRef = createServiceRef<FooService>({
|
||||
id: 'example.foo', // the owner of this service is in this case the 'example' plugin
|
||||
});
|
||||
```
|
||||
|
||||
The `fooServiceRef` that we create above should be exported, and can then be used to declare a dependency on the `FooService` interface and receive an implementation of it at runtime.
|
||||
|
||||
When creating a service reference you need to give it an ID. This ID needs to be globally unique, and should generally be of the format `'<pluginId>.<serviceName>'`. For more naming patters surrounding services, see the [naming patterns](./07-naming-patterns.md#services) page.
|
||||
|
||||
A note on naming: the frontend and backend systems intentionally use the separate names "APIs" and "Services" for concepts that are quite similar. This is to avoid confusion between the two, both in documentation and discussion, but also in code. While the two systems are quite similar, they are not identical, and they can't be used interchangeably.
|
||||
|
||||
## Service Factories
|
||||
|
||||
In order to be able to depend on a service interface through a service reference, we of course also need to have some way of creating the concrete implementation of it. To encapsulate that logic we use service factories, which define both how service instances are created, as well as what other services they depend on for their implementation.
|
||||
|
||||
Service factories can come from many different sources. There are built-in service factories, external ones that you can import from other packages, and you can also create your own. Specific service factories are installed within each backend instance, which acts as the dependency injection container. For any given backend instance there can only be a single designated service factory for each service.
|
||||
|
||||
To define a service factory, we use `createServiceFactory`:
|
||||
|
||||
```ts
|
||||
import { createServiceFactory } from '@backstage/backend-plugin-api';
|
||||
|
||||
class DefaultFooService implements FooService {
|
||||
async foo(options: FooOptions): Promise<FooResult> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
export const fooFactory = createServiceFactory({
|
||||
service: fooServiceRef,
|
||||
deps: { bar: barServiceRef },
|
||||
factory({ bar }) {
|
||||
return new DefaultFooService(bar);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To create a service factory we need to provide a reference to the `service` for which the factory will create instances, a `deps` object which lists the other services that the factory depends on, and a `factory` function which will be called to create the service instance. The backend system will call the `factory` function with an object that contains the service instances for each of the dependencies listed in the `deps` object. If a service implementation does not depend on any other services, the `deps` are left as an empty object (`{}`). The `factory` function must return a value that implements the service interface.
|
||||
|
||||
If you need the creation of the service instance to be asynchronous, you can make the `factory` function async. For example:
|
||||
|
||||
```ts
|
||||
export const fooFactory = createServiceFactory({
|
||||
service: fooServiceRef,
|
||||
deps: {},
|
||||
async factory() {
|
||||
const foo = new DefaultFooService();
|
||||
await foo.init();
|
||||
return foo;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note that circular dependencies among service factories are not allowed. This is verified at runtime, and your backend instance will refuse to start up if it detects any conflicts. Likewise, the backend will also fail to start up if a service factory depends on a service that is not provided by any registered service factory.
|
||||
|
||||
## Service Factory Options
|
||||
|
||||
To install a service factory in a backend instance, we pass it in through the `services` option to `createBackend`:
|
||||
|
||||
```ts
|
||||
const backend = createBackend({
|
||||
services: [fooFactory()],
|
||||
});
|
||||
```
|
||||
|
||||
Note that we call `fooFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. This is done to always allow for options to be added to the service factory in the future, without breaking existing code. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. For example:
|
||||
|
||||
```ts
|
||||
export interface FooFactoryOptions {
|
||||
mode: 'eager' | 'lazy';
|
||||
}
|
||||
|
||||
export const fooFactory = createServiceFactory(
|
||||
(options?: FooFactoryOptions) => ({
|
||||
service: fooServiceRef,
|
||||
deps: { bar: barServiceRef },
|
||||
factory({ bar }) {
|
||||
return new DefaultFooService(bar, options?.mode);
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
This lets us use the options to customize the factory implementation in any way we want. From the outside the service factory looks just like before, except that we're now also able to pass options when installing the factory:
|
||||
|
||||
```ts
|
||||
const backend = createBackend({
|
||||
services: [fooFactory({ mode: 'eager' })],
|
||||
});
|
||||
```
|
||||
|
||||
## Core Services
|
||||
|
||||
The backend system provides a number of core service definitions that both help implement the main functionality of the backend, but also provide a set of utilities for common concerns, such as logging, database access, job scheduling, and so on. These core services will always be present in a backend instance created with `createBackend`, and they can all be overridden with custom implementations if needed.
|
||||
|
||||
The service references for all core services are exported via their own `coreServices` object, available from the `@backstage/backend-plugin-api` package. For example, the logging service is accessible via `coreServices.logger`.
|
||||
|
||||
You can read more about what core services there are and how to use them in the [core services](../core-services/01-index.md) section.
|
||||
|
||||
## Service Scope
|
||||
|
||||
By default services are scoped to individual plugins, meaning that separate instances of the service will be created for each plugin. For example, in our `fooFactory` above, a separate instance of `DefaultFooService` will be created for every plugin that depends on the service. This both makes it possible to tailor the service implementations for the individual plugins, and also ensures some level of separation between plugins.
|
||||
|
||||
The service scope is defined during the call to `createServiceRef`, with plugin scope being the default. Our above definition of the `fooServiceRef` is therefore equivalent to the following:
|
||||
|
||||
```ts
|
||||
export const fooServiceRef = createServiceRef<FooService>({
|
||||
scope: 'plugin',
|
||||
id: 'example.foo',
|
||||
});
|
||||
```
|
||||
|
||||
There are only two possible scopes for services, `'plugin'` and `'root'`.
|
||||
|
||||
## Root Scoped Services
|
||||
|
||||
If a service is defined as a root scoped service, the implementation created by the factory will be shared across all plugins and services. One other differentiating factory for root scoped services is that they are always initialized, regardless of whether any plugins depend on them or not. This makes them suitable for implementing backend-wide concerns that are not specific to any individual plugin.
|
||||
|
||||
There is a limitation in the usage of root scoped services, which is that their implementation can only depend on other root scoped services. Plugin scoped services on the other hand can depend on both root and plugin scoped services. Because of this limitation, one of the main reasons to define a root scoped services is to make it possible for other root scoped services to depend on it.
|
||||
|
||||
Because of these limitations and particular use-cases for root scoped services, they tend to be more rare than plugin scoped services. In general, you should prefer defining a service as plugin scoped, unless you are implementing either of the two mentioned use-cases.
|
||||
|
||||
Some services come in pairs of a plugin and a root scoped service definition. For example, the `rootLogger` service is a root scoped service, while the `logger` service is a plugin scoped service. The `rootLogger` service houses the main logging implementation, while the `logger` service simply builds upon the `rootLogger` to add plugin specific labels. This division exists so that other root scoped services also have access to a logging service, but it is always preferable if the split can be avoided. If you do end up implementing this pattern, the root scoped service should be prefixed with `root`, this is to encourage use of the plugin scoped service instead.
|
||||
|
||||
## Plugin Metadata
|
||||
|
||||
Plugin scoped services have access to a plugin metadata service, which is a special service provided by the backend system that is not possible to override. The plugin metadata service provides information about the plugin that a service instance is being created for. It is itself a plugin scoped service, and can be depended on like any other service through the `coreServices.pluginMetadata` reference.
|
||||
|
||||
The plugin metadata service is the base for all plugin specific customizations for services. For example, the default implementation of the plugin scoped logger service uses the plugin metadata service to attach the plugin ID as a field in all log messages:
|
||||
|
||||
```ts
|
||||
export const loggerFactory = createServiceFactory({
|
||||
service: coreServices.logger,
|
||||
deps: {
|
||||
rootLogger: coreServices.rootLogger,
|
||||
pluginMetadata: coreServices.pluginMetadata,
|
||||
},
|
||||
factory({ rootLogger, pluginMetadata }) {
|
||||
return rootLogger.child({ plugin: pluginMetadata.getId() });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Root Context for Service Factories
|
||||
|
||||
Some services may benefit from having a context that is shared across all instances of a service. This of course only applies to plugin scoped services, as root scoped services only ever have a single instance. The root context could for example be used for sharing a common connection pool for database access, generated secrets for development, or any other kind of shared facility. Note that you should not use this to share state between plugins in production, as that would be a violation of the [plugin isolation rule](./04-plugins.md#rules-of-plugins).
|
||||
|
||||
The root context is defined as part of the service factory by passing the `createRootContext` option:
|
||||
|
||||
```ts
|
||||
export const fooFactory = createServiceFactory({
|
||||
service: fooServiceRef,
|
||||
deps: { rootLogger: coreServices.rootLogger, bar: barServiceRef },
|
||||
createRootContext({ rootLogger }) {
|
||||
return new FooRootContext(rootLogger);
|
||||
}
|
||||
factory({ bar }, ctx) {
|
||||
return ctx.forPlugin(bar)
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Whatever value is returned by the `createRootContext` function will shared and passed as the second argument to each invocation of the `factory` function. That way you can create a shared context that is used in the creation of each plugin instance. Unlike the `factory` function, the `createRootContext` function will only receive root scoped services as its dependencies, but just like the `factory` function, it can also be `async`.
|
||||
|
||||
## Default Service Factories
|
||||
|
||||
There are a lot of services that are installed in any standard Backstage backend instance by default. You can expect these services to always exist, and do not need to take any additional steps to make them available. This is not necessarily true for services that you import from external packages, as the user of your plugin or module might not have installed a factory for that service in their backend. In order to avoid having to ask integrators of your plugin to install a service factory for a service that you depend on, it is possible to define a default factory for a service.
|
||||
|
||||
Default service factories are defined as part of the service reference by passing the `defaultFactory` option to `createServiceRef`:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createServiceFactory,
|
||||
coreServices,
|
||||
createServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ExampleImpl } from './ExampleImpl';
|
||||
|
||||
export interface ExampleApi {
|
||||
doSomething(): Promise<void>;
|
||||
}
|
||||
|
||||
export const exampleServiceRef = createServiceRef<ExampleApi>({
|
||||
id: 'example',
|
||||
scope: 'plugin', // can be 'root' or 'plugin'
|
||||
|
||||
// The defaultFactory is optional to implement but it will be used if no
|
||||
// other factory is provided to the backend. This allows for the backend
|
||||
// to provide a default implementation of the service without having to wire
|
||||
// it beforehand.
|
||||
export const fooServiceRef = createServiceRef<FooService>({
|
||||
id: 'example.foo',
|
||||
defaultFactory: async service =>
|
||||
createServiceFactory({
|
||||
service,
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
},
|
||||
// This root context method is only available for plugin scoped services.
|
||||
// It's only called once per backend instance.
|
||||
// Logger is available at the root context level as it's also a root
|
||||
// scoped service.
|
||||
createRootContext({ logger }) {
|
||||
return new ExampleImplFactory({ logger });
|
||||
},
|
||||
// Plugin is available as it's a plugin scoped service and will be
|
||||
// created once per plugin. The logger can be had here too if needed.
|
||||
// Both this anc the root context can also be async.
|
||||
factory({ logger, plugin }, rootContext) {
|
||||
// This block will be executed once for every plugin that depends on
|
||||
// this service
|
||||
logger.info('Initializing example service plugin instance');
|
||||
return rootContext.forPlugin(plugin.getId());
|
||||
deps: {},
|
||||
factory() {
|
||||
return new DefaultFooService();
|
||||
},
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
### Overriding Services
|
||||
Note that we don't use the `fooServiceRef` when creating our service factory, but instead use the `service` parameter in the default factory callback. This is because attempting to use `fooServiceRef` directly would result in a circular reference.
|
||||
|
||||
In this example we replace the default root logger service implementation with a custom one that streams logs to GCP. The `rootLoggerServiceRef` has a `'root'` scope, meaning there are no plugin-specific instances of this service.
|
||||
If a service defines a default factory, that factory will be used if there is no explicit factory registered in the backend for that service. This allows users of your service to directly import and use a service, without worrying about whether it is installed or not. It is recommended to always define a default factory for any service that you are exporting for use in other plugins or modules.
|
||||
|
||||
```ts
|
||||
import {
|
||||
createServiceFactory,
|
||||
rootLoggerServiceRef,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
// This custom implementation would typically live separately from
|
||||
// the backend setup code, either nearby such as in
|
||||
// packages/backend/src/services/logger/GoogleCloudLogger.ts
|
||||
// Or you can let it live in its own library package.
|
||||
class GoogleCloudLogger implements LoggerService {
|
||||
static factory = createServiceFactory({
|
||||
service: rootLoggerServiceRef,
|
||||
deps: {},
|
||||
factory() {
|
||||
return new GoogleCloudLogger();
|
||||
},
|
||||
});
|
||||
// custom implementation here ...
|
||||
}
|
||||
|
||||
// packages/backend/src/index.ts
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
// supplies additional or replacement services to the backend
|
||||
GoogleCloudLogger.factory(),
|
||||
],
|
||||
});
|
||||
```
|
||||
When defining a default factory for a service, it is possible for it to end up with duplicate implementations at runtime. This applies both to any shared root context in your factory, as well as plugin specific instances of your service. This is because package dependency version ranges may not line up perfectly, causing duplicate installations of the same package. This can happen both for two different plugins using the same service, but also across a plugin and its modules. If your service would break in this scenario, you should not define a default factory for it, but instead require that users of your service explicitly install a factory in their backend instance.
|
||||
|
||||
@@ -16,6 +16,12 @@ Backend [plugins](../architecture/04-plugins.md) and
|
||||
backend _features_, are the building blocks that adopters add to their
|
||||
[backends](../architecture/02-backends.md).
|
||||
|
||||
## Creating a new Plugin
|
||||
|
||||
This guide assumes that you already have a Backend project set up. Even if you only want to develop a single plugin for publishing, we still recommend that you do so in a standard Backstage monorepo project, as you often end up needing multiple packages. For instructions on how to set up a new project, see our [getting started](../../getting-started/index.md#prerequisites) documentation.
|
||||
|
||||
To create a Backend plugin, run `yarn new`, select `backend-plugin`, and fill out the rest of the prompts. This will create a new package at `plugins/<pluginId>-backend`, which will be the main entrypoint for your plugin.
|
||||
|
||||
## Plugins
|
||||
|
||||
A basic backend plugin might look as follows:
|
||||
|
||||
@@ -3,7 +3,7 @@ id: index
|
||||
title: The Backend System
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: The backend system
|
||||
description: The Backend System
|
||||
---
|
||||
|
||||
> **DISCLAIMER: The new backend system is under active development and is not considered stable**
|
||||
@@ -12,4 +12,4 @@ description: The backend system
|
||||
|
||||
The new backend system is under active development, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
|
||||
|
||||
You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
|
||||
You can find an example backend setup in [the `backend-next` package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
|
||||
|
||||
@@ -210,3 +210,156 @@ const highlightOverride = {
|
||||
[obj-mode]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#stream_object_mode
|
||||
[read-stream]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#readable-streams
|
||||
[async-gen]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_async_generators
|
||||
|
||||
## How to render search results using extensions
|
||||
|
||||
Extensions for search results let you customize components used to render search result items, It is possible to provide your own search result item extensions or use the ones provided by plugin packages:
|
||||
|
||||
### 1. Providing an extension in your plugin package
|
||||
|
||||
Using the example below, you can provide an extension to be used as a default result item:
|
||||
|
||||
```tsx
|
||||
// plugins/your-plugin/src/plugin.ts
|
||||
import { createPlugin } from '@backstage/core-plugin-api';
|
||||
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
|
||||
|
||||
const plugin = createPlugin({ id: 'YOUR_PLUGIN_ID' });
|
||||
|
||||
export const YourSearchResultListItemExtension = plugin.provide(
|
||||
createSearchResultListItemExtension({
|
||||
name: 'YourSearchResultListItem',
|
||||
component: () =>
|
||||
import('./components').then(m => m.YourSearchResultListItem),
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Additionally, you can define a predicate function that receives a result and returns whether your extension should be used to render it or not:
|
||||
|
||||
```tsx
|
||||
// plugins/your-plugin/src/plugin.ts
|
||||
import { createPlugin } from '@backstage/core-plugin-api';
|
||||
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
|
||||
|
||||
const plugin = createPlugin({ id: 'YOUR_PLUGIN_ID' });
|
||||
|
||||
export const YourSearchResultListItemExtension = plugin.provide(
|
||||
createSearchResultListItemExtension({
|
||||
name: 'YourSearchResultListItem',
|
||||
component: () =>
|
||||
import('./components').then(m => m.YourSearchResultListItem),
|
||||
// Only results matching your type will be rendered by this extension
|
||||
predicate: result => result.type === 'YOUR_RESULT_TYPE',
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Remember to export your new extension:
|
||||
|
||||
```tsx
|
||||
// plugins/your-plugin/src/index.ts
|
||||
export { YourSearchResultListItem } from './plugin.ts';
|
||||
```
|
||||
|
||||
For more details, see the [createSearchResultListItemExtension](https://backstage.io/docs/reference/plugin-search-react.createsearchresultlistitemextension) API reference.
|
||||
|
||||
### 2. Using an extension in your Backstage app
|
||||
|
||||
Now that you know how a search result item is provided, let's finally see how they can be used, for example, to compose a page in your application:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/components/searchPage.tsx
|
||||
import React from 'react';
|
||||
|
||||
import { Grid, Paper } from '@material-ui/core';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
|
||||
import {
|
||||
Page,
|
||||
Header,
|
||||
Content,
|
||||
DocsIcon,
|
||||
CatalogIcon,
|
||||
} from '@backstage/core-components';
|
||||
import { SearchBar, SearchResult } from '@backstage/plugin-search-react';
|
||||
|
||||
// Your search result item extension
|
||||
import { YourSearchResultListItem } from '@backstage/your-plugin';
|
||||
|
||||
// Extensions provided by other plugin developers
|
||||
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
|
||||
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
|
||||
import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized';
|
||||
|
||||
// This example omits other components, like filter and pagination
|
||||
const SearchPage = () => (
|
||||
<Page themeId="home">
|
||||
<Header title="Search" />
|
||||
<Content>
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={12}>
|
||||
<Paper>
|
||||
<SearchBar />
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SearchResult>
|
||||
<YourSearchResultListItem />
|
||||
<CatalogSearchResultListItem icon={<CatalogIcon />} />
|
||||
<TechDocsSearchResultListItem icon={<DocsIcon />} />
|
||||
<ToolSearchResultListItem icon={<BuildIcon />} />
|
||||
</SearchResult>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
|
||||
export const searchPage = <SearchPage />;
|
||||
```
|
||||
|
||||
> **Important**: A default result item extension should be placed as the last child, so it can be used only when no other extensions match the result being rendered. If a non-default extension is specified, the `DefaultResultListItem` component will be used.
|
||||
|
||||
As another example, here's a search modal that renders results with extensions:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/components/searchModal.tsx
|
||||
import React from 'react';
|
||||
|
||||
import { DialogContent, DialogTitle, Paper } from '@material-ui/core';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
|
||||
import { DocsIcon, CatalogIcon } from '@backstage/core-components';
|
||||
import { SearchBar, SearchResult } from '@backstage/plugin-search-react';
|
||||
|
||||
// Your search result item extension
|
||||
import { YourSearchResultListItem } from '@backstage/your-plugin';
|
||||
|
||||
// Extensions provided by other plugin developers
|
||||
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
|
||||
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
|
||||
import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized';
|
||||
|
||||
export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => (
|
||||
<>
|
||||
<DialogTitle>
|
||||
<Paper>
|
||||
<SearchBar />
|
||||
</Paper>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<SearchResult onClick={toggleModal}>
|
||||
<CatalogSearchResultListItem icon={<CatalogIcon />} />
|
||||
<TechDocsSearchResultListItem icon={<DocsIcon />} />
|
||||
<ToolSearchResultListItem icon={<BuildIcon />} />
|
||||
{/* As a "default" extension, it does not define a predicate function,
|
||||
so it must be the last child to render results that do not match the above extensions */}
|
||||
<YourSearchResultListItem />
|
||||
</SearchResult>
|
||||
</DialogContent>
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
There are other more specific search results layout components that also accept result item extensions, check their documentation: [SearchResultList](https://backstage.io/storybook/?path=/story/plugins-search-searchresultlist--with-result-item-extensions) and [SearchResultGroup](https://backstage.io/storybook/?path=/story/plugins-search-searchresultgroup--with-result-item-extensions).
|
||||
|
||||
@@ -35,7 +35,7 @@ import FormControl from '@material-ui/core/FormControl';
|
||||
/*
|
||||
This is the actual component that will get rendered in the form
|
||||
*/
|
||||
export const ValidateKebabCaseExtension = ({
|
||||
export const ValidateKebabCase = ({
|
||||
onChange,
|
||||
rawErrors,
|
||||
required,
|
||||
@@ -96,7 +96,7 @@ import {
|
||||
import {
|
||||
ValidateKebabCase,
|
||||
validateKebabCaseValidation,
|
||||
} from './ValidateKebabCase';
|
||||
} from './ValidateKebabCase/ValidateKebabCaseExtension';
|
||||
|
||||
export const ValidateKebabCaseFieldExtension = scaffolderPlugin.provide(
|
||||
createScaffolderFieldExtension({
|
||||
@@ -173,7 +173,7 @@ spec:
|
||||
title: Name
|
||||
type: string
|
||||
description: My custom name for the component
|
||||
ui:field: ValidateKebabCaseExtension
|
||||
ui:field: ValidateKebabCase
|
||||
steps:
|
||||
[...]
|
||||
```
|
||||
|
||||
@@ -49,7 +49,7 @@ techdocs:
|
||||
# will be broken in these scenarios.
|
||||
legacyCopyReadmeMdToIndexMd: false
|
||||
|
||||
# techdocs.builder can be either 'local' or 'external.
|
||||
# techdocs.builder can be either 'local' or 'external'.
|
||||
# Using the default build strategy, if builder is set to 'local' and you open a TechDocs page,
|
||||
# techdocs-backend will try to generate the docs, publish to storage and show the generated docs afterwords.
|
||||
# This is the "Basic" setup of the TechDocs Architecture.
|
||||
|
||||
@@ -230,7 +230,7 @@ If you are deploying Backstage to Amazon EC2, Amazon ECS, or Amazon EKS, you do
|
||||
not need to obtain the access keys separately. They can be made available in the
|
||||
environment automatically by defining appropriate IAM role with access to the
|
||||
bucket. Read more in the
|
||||
[official AWS documentation for using IAM roles.](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html#use-roles).
|
||||
[official AWS documentation for using IAM roles](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html#use-roles).
|
||||
|
||||
**4b. Authentication using app-config.yaml**
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ catalog:
|
||||
frequency: { minutes: 30 }
|
||||
# supports ISO duration, "human duration" as used in code
|
||||
timeout: { minutes: 3 }
|
||||
yourSecondProviderId: # identifies your dataset / provider independent of config changes
|
||||
organization: myorg
|
||||
project: '*' # this will match all projects
|
||||
repository: '*' # this will match all repos
|
||||
path: /catalog-info.yaml
|
||||
anotherProviderId: # another identifier
|
||||
organization: myorg
|
||||
project: myproject
|
||||
@@ -62,7 +67,7 @@ The parameters available are:
|
||||
|
||||
- **`host:`** _(optional)_ Leave empty for Cloud hosted, otherwise set to your self-hosted instance host.
|
||||
- **`organization:`** Your Organization slug (or Collection for on-premise users). Required.
|
||||
- **`project:`** Your project slug. Required.
|
||||
- **`project:`** _(optional)_ Your project slug. Wildcards are supported as show on the examples above. If not set, all projects will be searched.
|
||||
- **`repository:`** _(optional)_ The repository name. Wildcards are supported as show on the examples above. If not set, all repositories will be searched.
|
||||
- **`path:`** _(optional)_ Where to find catalog-info.yaml files. Defaults to /catalog-info.yaml.
|
||||
- **`schedule`** _(optional)_:
|
||||
@@ -144,7 +149,7 @@ When using a custom pattern, the target is composed of five parts:
|
||||
|
||||
- The base instance URL, `https://dev.azure.com` in this case
|
||||
- The organization name which is required, `myorg` in this case
|
||||
- The project name which is required, `myproject` in this case
|
||||
- The project name which is optional, `myproject` in this case. This defaults to \*, which scans all the projects where the token has access to.
|
||||
- The repository blob to scan, which accepts \* wildcard tokens and must be
|
||||
added after `_git/`. This can simply be `*` to scan all repositories in the
|
||||
project.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: org
|
||||
title: GitLab Organizational Data
|
||||
sidebar_label: Org Data
|
||||
description: Importing users and groups from a GitLab organization into Backstage
|
||||
---
|
||||
|
||||
The Backstage catalog can be set up to ingest organizational data - users and
|
||||
teams - directly from an organization in GitLab. The result
|
||||
is a hierarchy of
|
||||
[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and
|
||||
[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind
|
||||
entities that mirror your org setup.
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
gitlab:
|
||||
- host: gitlab.com
|
||||
token: ${GITLAB_TOKEN}
|
||||
```
|
||||
|
||||
This will query all users and groups from your gitlab installation. Depending on the size
|
||||
of the Gitlab Instance, this can take some time our resources.
|
||||
|
||||
The token that is used for the Organization Integration, has to be an Admin PAT.
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
providers:
|
||||
gitlab:
|
||||
yourProviderId:
|
||||
host: gitlab.com
|
||||
orgEnabled: true
|
||||
```
|
||||
@@ -37,7 +37,6 @@ schedule it:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugins/catalog.ts
|
||||
+import { Duration } from 'luxon';
|
||||
+import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap';
|
||||
|
||||
export default async function createPlugin(
|
||||
|
||||
@@ -28,6 +28,8 @@ Other responsibilities include protecting the integrity of configuration files a
|
||||
|
||||
The integrator is ultimately responsible for auditing usage of internal and external plugins as these run on the host system and have access to configuration and secrets. When installing plugins from sources like NPM, you should vet these in the same way that you would vet any other package installed from that source.
|
||||
|
||||
The integrator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible.
|
||||
|
||||
## Common Backend Configuration
|
||||
|
||||
There are many common facilities that are configured centrally and available to all Backstage backend plugins. For example there is a `DatabaseManager` that provides access to a SQL database, `TaskScheduler` for scheduling long-running tasks, `Logger` as a general logging facility, and `UrlReader` for reading content from external sources. These are all configured either directly in code, or within the `backend` block of the static configuration. The appropriate care needs to be taken to ensure that any secrets remain confidential and no malicious configuration is injected.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: S3 Viewer
|
||||
author: Spreadgroup
|
||||
authorUrl: https://github.com/spreadshirt
|
||||
category: AWS
|
||||
description: Visualization of S3 buckets and their contents in file explorer style.
|
||||
documentation: https://github.com/spreadshirt/backstage-plugin-s3/
|
||||
iconUrl: img/s3-bucket.svg
|
||||
npmPackageName: '@spreadshirt/backstage-plugin-s3-viewer'
|
||||
tags:
|
||||
- s3
|
||||
addedDate: '2023-01-18'
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Torque
|
||||
author: Quali
|
||||
authorUrl: 'https://www.qtorque.io/'
|
||||
category: Orchestration
|
||||
description: |
|
||||
Deploy the environments you need to keep building, testing and delivering incredible code.
|
||||
Plugin includes an Entity ComponentCard, Backend API route and scaffolder actions.
|
||||
documentation: https://github.com/QualiTorque/torque-backstage-plugin/tree/main/packages/torque#readme
|
||||
iconUrl: https://user-images.githubusercontent.com/8643801/214640977-751bc338-6b77-40a0-a897-cba41b6f006a.png
|
||||
npmPackageName: '@qtorque/backstage-plugin-torque'
|
||||
addedDate: '2023-01-25'
|
||||
@@ -20,7 +20,7 @@ const ondemandMetadata = fs
|
||||
.reverse()
|
||||
.map(file => yaml.load(fs.readFileSync(`./data/on-demand/${file}`, 'utf8')));
|
||||
const truncate = text =>
|
||||
text.length > 170 ? text.substr(0, 170) + '...' : text;
|
||||
text.length > 170 ? text.slice(0, 170) + '...' : text;
|
||||
|
||||
const addVideoDocsLink = '/docs/overview/support';
|
||||
const defaultIconUrl = 'img/logo-gradient-on-dark.svg';
|
||||
|
||||
@@ -19,7 +19,7 @@ const pluginMetadata = fs
|
||||
.map(file => yaml.load(fs.readFileSync(`./data/plugins/${file}`, 'utf8')))
|
||||
.sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase()));
|
||||
const truncate = text =>
|
||||
text.length > 170 ? text.substr(0, 170) + '...' : text;
|
||||
text.length > 170 ? text.slice(0, 170) + '...' : text;
|
||||
|
||||
const newForDays = 100;
|
||||
|
||||
|
||||
@@ -201,7 +201,8 @@
|
||||
"label": "GitLab",
|
||||
"ids": [
|
||||
"integrations/gitlab/locations",
|
||||
"integrations/gitlab/discovery"
|
||||
"integrations/gitlab/discovery",
|
||||
"integrations/gitlab/org"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -138,8 +138,9 @@ const siteConfig = {
|
||||
],
|
||||
|
||||
algolia: {
|
||||
apiKey: '8d115c9875ba0f4feaee95bab55a1645',
|
||||
indexName: 'backstage',
|
||||
apiKey: '10b9e6c92a4513c1cf390f50e53aad1f',
|
||||
indexName: 'backstage_io',
|
||||
appId: 'JCMFNHCHI8',
|
||||
searchParameters: {}, // Optional (if provided by Algolia)
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 100 100" height="100px" version="1.1" viewBox="0 0 100 100" width="100px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_1"><g><g><g enable-background="new "><g enable-background="new "><defs><path d="M77.586,28.061v2.772c0,3.559-12.344,6.433-27.578,6.433 c-15.25,0-27.594-2.874-27.594-6.433v-2.772c0,3.559,12.344,6.432,27.594,6.432C65.242,34.492,77.586,31.619,77.586,28.061z" enable-background="new " id="SVGID_5_"/></defs><clipPath id="SVGID_2_"/><g clip-path="url(#SVGID_2_)" enable-background="new "><path d="M77.586,28.061v2.772c0,0.084-0.006,0.168-0.02,0.25v-2.771C77.58,28.228,77.586,28.145,77.586,28.061 " fill="#8C3323"/><path d="M77.566,28.312v2.771c-0.018,0.098-0.039,0.193-0.074,0.289v-2.773 C77.527,28.503,77.549,28.407,77.566,28.312" fill="#8C3323"/><path d="M77.492,28.599v2.773c-0.049,0.135-0.113,0.268-0.195,0.4v-2.773 C77.379,28.866,77.443,28.734,77.492,28.599" fill="#8C3323"/><path d="M77.297,28.999v2.773c-1.945,3.111-13.42,5.493-27.289,5.493c-15.25,0-27.594-2.874-27.594-6.433 v-2.772c0,3.559,12.344,6.432,27.594,6.432C63.877,34.492,75.352,32.11,77.297,28.999" fill="#8C3323"/></g></g><g><path d="M50.008,21.628c15.234,0,27.578,2.875,27.578,6.433c0,3.559-12.344,6.432-27.578,6.432 c-15.25,0-27.594-2.873-27.594-6.432C22.414,24.503,34.758,21.628,50.008,21.628z" fill="#E15343"/></g><g><polygon fill="#8C3323" points="77.428,33.006 77.428,35.779 68.387,74.069 67.67,72.257 "/></g><g><polygon fill="#8C3323" points="31.613,71.296 31.613,74.069 22.572,35.779 22.572,33.006 "/></g><g enable-background="new "><defs><path d="M68.387,71.296v2.773c0,2.387-8.217,4.303-18.379,4.303 s-18.395-1.916-18.395-4.303v-2.773c0,2.389,8.232,4.303,18.395,4.303S68.387,73.685,68.387,71.296z" enable-background="new " id="SVGID_7_"/></defs><clipPath id="SVGID_4_"/><g clip-path="url(#SVGID_4_)" enable-background="new "><path d="M68.387,71.296v2.773c0,0.057-0.004,0.112-0.012,0.168v-2.771 C68.383,71.409,68.387,71.353,68.387,71.296" fill="#8C3323"/><path d="M68.375,71.466v2.771c-0.012,0.066-0.027,0.131-0.051,0.196v-2.772 C68.348,71.596,68.363,71.53,68.375,71.466" fill="#8C3323"/><path d="M68.324,71.661v2.772c-0.033,0.091-0.076,0.18-0.131,0.268v-2.772 C68.248,71.839,68.291,71.751,68.324,71.661" fill="#8C3323"/><path d="M68.67,71.007l-0.477,3.694c-1.301,2.084-8.939,3.671-18.186,3.671 c-10.162,0-18.395-1.916-18.395-4.303v-2.773c0,2.389,8.232,4.303,18.395,4.303c9.246,0,16.885-1.585,18.186-3.67" fill="#8C3323"/></g></g><g><path d="M50.008,38.752c14.24,0,25.951-2.515,27.42-5.746l-9.041,38.29c0,2.389-8.217,4.303-18.379,4.303 s-18.395-1.914-18.395-4.303l-9.041-38.29C24.043,36.237,35.77,38.752,50.008,38.752z" fill="#E15343"/></g></g></g><rect clip-rule="evenodd" fill="#FFFFFF" fill-rule="evenodd" height="11.398" width="11.477" x="43.762" y="42.854"/><ellipse clip-rule="evenodd" cx="40.287" cy="63.9" fill="#FFFFFF" fill-rule="evenodd" rx="5.658" ry="5.62"/><polygon clip-rule="evenodd" fill="#FFFFFF" fill-rule="evenodd" points="64.09,69.257 52.748,69.257 58.42,58.784 "/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
+1
-1
@@ -46,7 +46,7 @@
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17"
|
||||
},
|
||||
"version": "1.11.0-next.0",
|
||||
"version": "1.11.0-next.1",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3"
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.1.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-app-api@1.4.1-next.0
|
||||
- @backstage/core-components@0.12.4-next.0
|
||||
- @backstage/core-plugin-api@1.3.0
|
||||
- @backstage/theme@0.2.16
|
||||
- @backstage/plugin-permission-react@0.4.9
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1-next.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.80-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-scaffolder-react@1.1.0-next.1
|
||||
- @backstage/plugin-scaffolder@1.11.0-next.1
|
||||
- @backstage/cli@0.22.2-next.0
|
||||
- @backstage/plugin-techdocs@1.5.0-next.1
|
||||
- @backstage/plugin-tech-insights@0.3.7-next.1
|
||||
- @backstage/plugin-search@1.1.0-next.1
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.0.10-next.1
|
||||
- @backstage/plugin-dynatrace@2.0.0-next.1
|
||||
- @backstage/plugin-playlist@0.1.6-next.1
|
||||
- @backstage/plugin-home@0.4.31-next.1
|
||||
- @backstage/core-app-api@1.4.1-next.0
|
||||
- @backstage/plugin-kubernetes@0.7.8-next.1
|
||||
- @backstage/core-components@0.12.4-next.0
|
||||
- @backstage/plugin-tech-radar@0.6.1-next.0
|
||||
- @backstage/plugin-explore@0.4.0-next.1
|
||||
- @backstage/plugin-apache-airflow@0.2.8-next.0
|
||||
- @backstage/plugin-circleci@0.3.15-next.1
|
||||
- @backstage/plugin-sentry@0.4.8-next.1
|
||||
- @backstage/plugin-search-react@1.5.0-next.0
|
||||
- @backstage/plugin-airbrake@0.3.15-next.1
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.1
|
||||
- @backstage/app-defaults@1.1.1-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/core-plugin-api@1.3.0
|
||||
- @backstage/integration-react@1.1.10-next.0
|
||||
- @backstage/theme@0.2.16
|
||||
- @backstage/plugin-api-docs@0.8.15-next.1
|
||||
- @backstage/plugin-azure-devops@0.2.6-next.1
|
||||
- @backstage/plugin-azure-sites@0.1.4-next.1
|
||||
- @backstage/plugin-badges@0.2.39-next.1
|
||||
- @backstage/plugin-catalog-common@1.0.11-next.0
|
||||
- @backstage/plugin-catalog-graph@0.2.27-next.1
|
||||
- @backstage/plugin-catalog-import@0.9.5-next.1
|
||||
- @backstage/plugin-cloudbuild@0.3.15-next.1
|
||||
- @backstage/plugin-code-coverage@0.2.8-next.1
|
||||
- @backstage/plugin-cost-insights@0.12.4-next.1
|
||||
- @backstage/plugin-gcalendar@0.3.11-next.0
|
||||
- @backstage/plugin-gcp-projects@0.3.34-next.0
|
||||
- @backstage/plugin-github-actions@0.5.15-next.1
|
||||
- @backstage/plugin-gocd@0.1.21-next.1
|
||||
- @backstage/plugin-graphiql@0.2.47-next.0
|
||||
- @backstage/plugin-jenkins@0.7.14-next.1
|
||||
- @backstage/plugin-kafka@0.3.15-next.1
|
||||
- @backstage/plugin-lighthouse@0.3.15-next.1
|
||||
- @backstage/plugin-newrelic@0.3.33-next.0
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.8-next.1
|
||||
- @backstage/plugin-org@0.6.5-next.1
|
||||
- @backstage/plugin-pagerduty@0.5.8-next.1
|
||||
- @backstage/plugin-permission-react@0.4.9
|
||||
- @backstage/plugin-rollbar@0.4.15-next.1
|
||||
- @backstage/plugin-search-common@1.2.1
|
||||
- @backstage/plugin-shortcuts@0.3.7-next.0
|
||||
- @backstage/plugin-stack-overflow@0.1.11-next.1
|
||||
- @backstage/plugin-techdocs-react@1.1.3-next.1
|
||||
- @backstage/plugin-todo@0.2.17-next.1
|
||||
- @backstage/plugin-user-settings@0.6.3-next.1
|
||||
- @internal/plugin-catalog-customized@0.0.7-next.1
|
||||
|
||||
## 0.2.80-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.80-next.0",
|
||||
"version": "0.2.80-next.1",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
List,
|
||||
makeStyles,
|
||||
Paper,
|
||||
useTheme,
|
||||
@@ -44,9 +43,8 @@ import {
|
||||
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
|
||||
import { searchPlugin, SearchType } from '@backstage/plugin-search';
|
||||
import {
|
||||
DefaultResultListItem,
|
||||
SearchFilter,
|
||||
SearchBar,
|
||||
SearchFilter,
|
||||
SearchResult,
|
||||
SearchResultPager,
|
||||
useSearch,
|
||||
@@ -93,7 +91,7 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
|
||||
searchBarRef?.current?.focus();
|
||||
});
|
||||
|
||||
const handleSearchResulClick = useCallback(() => {
|
||||
const handleSearchResultClick = useCallback(() => {
|
||||
toggleModal();
|
||||
setTimeout(focusContent, transitions.duration.leavingScreen);
|
||||
}, [toggleModal, focusContent, transitions]);
|
||||
@@ -101,11 +99,11 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
|
||||
const handleSearchBarKeyDown = useCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleSearchResultClick();
|
||||
navigate(searchPagePath);
|
||||
toggleModal();
|
||||
}
|
||||
},
|
||||
[navigate, toggleModal, searchPagePath],
|
||||
[navigate, searchPagePath, handleSearchResultClick],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -189,7 +187,7 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Grid item>
|
||||
<Link to={searchPagePath} onClick={handleSearchResulClick}>
|
||||
<Link to={searchPagePath} onClick={handleSearchResultClick}>
|
||||
<Typography
|
||||
component="span"
|
||||
className={classes.viewResultsLink}
|
||||
@@ -202,69 +200,13 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
{results.map(({ type, document, highlight, rank }) => {
|
||||
let resultItem;
|
||||
switch (type) {
|
||||
case 'software-catalog':
|
||||
resultItem = (
|
||||
<CatalogSearchResultListItem
|
||||
icon={<CatalogIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'techdocs':
|
||||
resultItem = (
|
||||
<TechDocsSearchResultListItem
|
||||
icon={<DocsIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'tools':
|
||||
resultItem = (
|
||||
<ToolSearchResultListItem
|
||||
icon={<BuildIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
resultItem = (
|
||||
<DefaultResultListItem
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
key={`${document.location}-btn`}
|
||||
onClick={handleSearchResulClick}
|
||||
onKeyDown={handleSearchResulClick}
|
||||
>
|
||||
{resultItem}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
<SearchResult
|
||||
onClick={handleSearchResultClick}
|
||||
onKeyDown={handleSearchResultClick}
|
||||
>
|
||||
<CatalogSearchResultListItem icon={<CatalogIcon />} />
|
||||
<TechDocsSearchResultListItem icon={<DocsIcon />} />
|
||||
<ToolSearchResultListItem icon={<BuildIcon />} />
|
||||
</SearchResult>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -30,16 +30,15 @@ import {
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { SearchType } from '@backstage/plugin-search';
|
||||
import {
|
||||
DefaultResultListItem,
|
||||
SearchBar,
|
||||
SearchFilter,
|
||||
SearchResult,
|
||||
SearchPagination,
|
||||
SearchResult,
|
||||
SearchResultPager,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
|
||||
import { Grid, List, makeStyles, Paper, Theme } from '@material-ui/core';
|
||||
import { Grid, makeStyles, Paper, Theme } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
@@ -133,53 +132,9 @@ const SearchPage = () => {
|
||||
<Grid item xs>
|
||||
<SearchPagination />
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
{results.map(({ type, document, highlight, rank }) => {
|
||||
switch (type) {
|
||||
case 'software-catalog':
|
||||
return (
|
||||
<CatalogSearchResultListItem
|
||||
icon={<CatalogIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
case 'techdocs':
|
||||
return (
|
||||
<TechDocsSearchResultListItem
|
||||
icon={<DocsIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
case 'tools':
|
||||
return (
|
||||
<ToolSearchResultListItem
|
||||
icon={<BuildIcon />}
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<DefaultResultListItem
|
||||
key={document.location}
|
||||
result={document}
|
||||
highlight={highlight}
|
||||
rank={rank}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
<CatalogSearchResultListItem icon={<CatalogIcon />} />
|
||||
<TechDocsSearchResultListItem icon={<DocsIcon />} />
|
||||
<ToolSearchResultListItem icon={<BuildIcon />} />
|
||||
</SearchResult>
|
||||
<SearchResultPager />
|
||||
</Grid>
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.3.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.1
|
||||
- @backstage/backend-plugin-api@0.3.2-next.1
|
||||
- @backstage/backend-tasks@0.4.3-next.1
|
||||
- @backstage/cli-common@0.1.11
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/config-loader@1.1.8
|
||||
- @backstage/errors@1.1.4
|
||||
- @backstage/types@1.0.2
|
||||
- @backstage/plugin-auth-node@0.2.11-next.1
|
||||
- @backstage/plugin-permission-node@0.7.5-next.1
|
||||
|
||||
## 0.3.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.3.2-next.0",
|
||||
"version": "0.3.2-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
@@ -64,6 +64,7 @@
|
||||
"winston-transport": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/fs-extra": "^9.0.3",
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { startTestBackend } from '@backstage/backend-test-utils';
|
||||
import { schedulerFactory } from './schedulerFactory';
|
||||
|
||||
describe('schedulerFactory', () => {
|
||||
it('creates sidecar database features', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const subject = schedulerFactory();
|
||||
|
||||
const plugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
scheduler: subject.service,
|
||||
database: coreServices.database,
|
||||
},
|
||||
init: async ({ scheduler, database }) => {
|
||||
await scheduler.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: { seconds: 1 },
|
||||
frequency: { seconds: 1 },
|
||||
fn: async () => {},
|
||||
});
|
||||
|
||||
const client = await database.getClient();
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__tasks').count(),
|
||||
).resolves.toEqual([{ 'count(*)': 1 }]);
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__knex_migrations').count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
await expect(
|
||||
client
|
||||
.from('backstage_backend_tasks__knex_migrations_lock')
|
||||
.count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await startTestBackend({
|
||||
features: [plugin()],
|
||||
services: [subject],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,20 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.18.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 628e2bd89a: Updated dependency `@kubernetes/client-node` to `0.18.1`.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.3.2-next.1
|
||||
- @backstage/backend-app-api@0.3.2-next.1
|
||||
- @backstage/cli-common@0.1.11
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/config-loader@1.1.8
|
||||
- @backstage/errors@1.1.4
|
||||
- @backstage/integration@1.4.2
|
||||
- @backstage/types@1.0.2
|
||||
|
||||
## 0.18.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.18.2-next.0",
|
||||
"version": "0.18.2-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.1.7-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.3.2-next.1
|
||||
- @backstage/backend-app-api@0.3.2-next.1
|
||||
|
||||
## 0.1.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.1.7-next.0",
|
||||
"version": "0.1.7-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.8-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-backend@1.7.2-next.1
|
||||
- @backstage/plugin-scaffolder-backend@1.11.0-next.1
|
||||
- @backstage/backend-defaults@0.1.7-next.1
|
||||
- @backstage/plugin-app-backend@0.3.42-next.1
|
||||
|
||||
## 0.0.8-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.8-next.0",
|
||||
"version": "0.0.8-next.1",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.3.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ae88f61e00: The `register` methods passed to `createBackendPlugin` and `createBackendModule`
|
||||
now have dedicated `BackendPluginRegistrationPoints` and
|
||||
`BackendModuleRegistrationPoints` arguments, respectively. This lets us make it
|
||||
clear on a type level that it's not possible to pass in extension points as
|
||||
dependencies to plugins (should only ever be done for modules). This has no
|
||||
practical effect on code that was already well behaved.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-tasks@0.4.3-next.1
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/types@1.0.2
|
||||
- @backstage/plugin-auth-node@0.2.11-next.1
|
||||
- @backstage/plugin-permission-common@0.7.3
|
||||
|
||||
## 0.3.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -22,27 +22,57 @@ export interface BackendFeature {
|
||||
register(reg: BackendRegistrationPoints): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BackendModuleConfig {
|
||||
// (undocumented)
|
||||
moduleId: string;
|
||||
// (undocumented)
|
||||
pluginId: string;
|
||||
// (undocumented)
|
||||
register(
|
||||
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
|
||||
): void;
|
||||
register(reg: BackendModuleRegistrationPoints): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface BackendPluginConfig {
|
||||
// @public
|
||||
export interface BackendModuleRegistrationPoints {
|
||||
// (undocumented)
|
||||
registerInit<
|
||||
Deps extends {
|
||||
[name in string]: unknown;
|
||||
},
|
||||
>(options: {
|
||||
deps: {
|
||||
[name in keyof Deps]: ServiceRef<Deps[name]> | ExtensionPoint<Deps[name]>;
|
||||
};
|
||||
init(deps: Deps): Promise<void>;
|
||||
}): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface BackendPluginConfig {
|
||||
id: string;
|
||||
// (undocumented)
|
||||
register(reg: BackendRegistrationPoints): void;
|
||||
register(reg: BackendPluginRegistrationPoints): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BackendPluginRegistrationPoints {
|
||||
// (undocumented)
|
||||
registerExtensionPoint<TExtensionPoint>(
|
||||
ref: ExtensionPoint<TExtensionPoint>,
|
||||
impl: TExtensionPoint,
|
||||
): void;
|
||||
// (undocumented)
|
||||
registerInit<
|
||||
Deps extends {
|
||||
[name in string]: unknown;
|
||||
},
|
||||
>(options: {
|
||||
deps: {
|
||||
[name in keyof Deps]: ServiceRef<Deps[name]>;
|
||||
};
|
||||
init(deps: Deps): Promise<void>;
|
||||
}): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface BackendRegistrationPoints {
|
||||
// (undocumented)
|
||||
registerExtensionPoint<TExtensionPoint>(
|
||||
@@ -116,12 +146,12 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
|
||||
): (...params: TOptions) => BackendFeature;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
|
||||
): (...params: TOptions) => BackendFeature;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function createExtensionPoint<T>(
|
||||
config: ExtensionPointConfig,
|
||||
): ExtensionPoint<T>;
|
||||
@@ -248,9 +278,8 @@ export type ExtensionPoint<T> = {
|
||||
$$ref: 'extension-point';
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface ExtensionPointConfig {
|
||||
// (undocumented)
|
||||
id: string;
|
||||
}
|
||||
|
||||
@@ -476,13 +505,13 @@ export interface ServiceRefConfig<TService, TScope extends 'root' | 'plugin'> {
|
||||
scope?: TScope;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface SharedBackendEnvironment {
|
||||
// (undocumented)
|
||||
$$type: 'SharedBackendEnvironment';
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface SharedBackendEnvironmentConfig {
|
||||
// (undocumented)
|
||||
services?: ServiceFactoryOrFunction[];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"version": "0.3.2-next.0",
|
||||
"version": "0.3.2-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -16,35 +16,47 @@
|
||||
|
||||
import { ServiceFactory, ServiceFactoryOrFunction } from '../services';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* The configuration options passed to {@link createSharedEnvironment}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface SharedBackendEnvironmentConfig {
|
||||
services?: ServiceFactoryOrFunction[];
|
||||
}
|
||||
|
||||
// This type is opaque in order to allow for future API evolution without
|
||||
// cluttering the external API. For example we might want to add support
|
||||
// for more powerful callback based backend modifications.
|
||||
//
|
||||
// By making this opaque we also ensure that the type doesn't become an input
|
||||
// type that we need to care about, as it would otherwise be possible to pass
|
||||
// a custom environment definition to `createBackend`, which we don't want.
|
||||
/**
|
||||
* An opaque type that represents the contents of a shared backend environment.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface SharedBackendEnvironment {
|
||||
$$type: 'SharedBackendEnvironment';
|
||||
|
||||
// NOTE: This type is opaque in order to allow for future API evolution without
|
||||
// cluttering the external API. For example we might want to add support
|
||||
// for more powerful callback based backend modifications.
|
||||
//
|
||||
// By making this opaque we also ensure that the type doesn't become an input
|
||||
// type that we need to care about, as it would otherwise be possible to pass
|
||||
// a custom environment definition to `createBackend`, which we don't want.
|
||||
}
|
||||
|
||||
/**
|
||||
* This type is NOT supposed to be used by anyone except internally by the backend-app-api package.
|
||||
* @internal */
|
||||
* This type is NOT supposed to be used by anyone except internally by the
|
||||
* backend-app-api package.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface InternalSharedBackendEnvironment {
|
||||
version: 'v1';
|
||||
services?: ServiceFactory[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shared backend environment which can be used to create multiple backends
|
||||
* Creates a shared backend environment which can be used to create multiple
|
||||
* backends.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createSharedEnvironment<
|
||||
|
||||
@@ -15,17 +15,35 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
BackendModuleRegistrationPoints,
|
||||
BackendPluginRegistrationPoints,
|
||||
BackendRegistrationPoints,
|
||||
BackendFeature,
|
||||
ExtensionPoint,
|
||||
} from './types';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* The configuration options passed to {@link createExtensionPoint}.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export interface ExtensionPointConfig {
|
||||
/**
|
||||
* The ID of this extension point.
|
||||
*
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Creates a new backend extension point.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points}
|
||||
*/
|
||||
export function createExtensionPoint<T>(
|
||||
config: ExtensionPointConfig,
|
||||
): ExtensionPoint<T> {
|
||||
@@ -41,13 +59,30 @@ export function createExtensionPoint<T>(
|
||||
};
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* The configuration options passed to {@link createBackendPlugin}.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export interface BackendPluginConfig {
|
||||
/**
|
||||
* The ID of this plugin.
|
||||
*
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
id: string;
|
||||
register(reg: BackendRegistrationPoints): void;
|
||||
register(reg: BackendPluginRegistrationPoints): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Creates a new backend plugin.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
|
||||
): (...params: TOptions) => BackendFeature {
|
||||
@@ -58,28 +93,33 @@ export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
return () => config;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* The configuration options passed to {@link createBackendModule}.
|
||||
*
|
||||
* @public
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export interface BackendModuleConfig {
|
||||
/**
|
||||
* The ID of this plugin.
|
||||
*
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
pluginId: string;
|
||||
/**
|
||||
* Should exactly match the `id` of the plugin that the module extends.
|
||||
*/
|
||||
moduleId: string;
|
||||
register(
|
||||
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
|
||||
): void;
|
||||
register(reg: BackendModuleRegistrationPoints): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new backend module for a given plugin.
|
||||
*
|
||||
* @public
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The `moduleId` should be equal to the module-specific suffix of the exported name, such
|
||||
* that the full name is `pluginId + "Module" + ModuleId`. For example, a GitHub entity
|
||||
* provider module for the `catalog` plugin might have the module ID `'githubEntityProvider'`,
|
||||
* and the full exported name would be `catalogModuleGithubEntityProvider`.
|
||||
*
|
||||
* The `pluginId` should exactly match the `id` of the plugin that the module extends.
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
|
||||
@@ -96,8 +136,9 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
return () => ({
|
||||
id: `${config.pluginId}.${config.moduleId}`,
|
||||
register(register: BackendRegistrationPoints) {
|
||||
// TODO: Hide registerExtensionPoint
|
||||
return config.register(register);
|
||||
return config.register({
|
||||
registerInit: register.registerInit.bind(register),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ export {
|
||||
createExtensionPoint,
|
||||
} from './factories';
|
||||
export type {
|
||||
BackendModuleRegistrationPoints,
|
||||
BackendPluginRegistrationPoints,
|
||||
BackendRegistrationPoints,
|
||||
BackendFeature,
|
||||
ExtensionPoint,
|
||||
|
||||
@@ -35,7 +35,13 @@ export type ExtensionPoint<T> = {
|
||||
$$ref: 'extension-point';
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* The callbacks passed to the `register` method of a backend feature; this is
|
||||
* essentially a superset of {@link BackendPluginRegistrationPoints} and
|
||||
* {@link BackendModuleRegistrationPoints}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BackendRegistrationPoints {
|
||||
registerExtensionPoint<TExtensionPoint>(
|
||||
ref: ExtensionPoint<TExtensionPoint>,
|
||||
@@ -49,6 +55,38 @@ export interface BackendRegistrationPoints {
|
||||
}): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The callbacks passed to the `register` method of a backend plugin.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BackendPluginRegistrationPoints {
|
||||
registerExtensionPoint<TExtensionPoint>(
|
||||
ref: ExtensionPoint<TExtensionPoint>,
|
||||
impl: TExtensionPoint,
|
||||
): void;
|
||||
registerInit<Deps extends { [name in string]: unknown }>(options: {
|
||||
deps: {
|
||||
[name in keyof Deps]: ServiceRef<Deps[name]>;
|
||||
};
|
||||
init(deps: Deps): Promise<void>;
|
||||
}): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The callbacks passed to the `register` method of a backend module.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BackendModuleRegistrationPoints {
|
||||
registerInit<Deps extends { [name in string]: unknown }>(options: {
|
||||
deps: {
|
||||
[name in keyof Deps]: ServiceRef<Deps[name]> | ExtensionPoint<Deps[name]>;
|
||||
};
|
||||
init(deps: Deps): Promise<void>;
|
||||
}): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface BackendFeature {
|
||||
// TODO(Rugvip): Try to get rid of the ID at this level, allowing for a feature to register multiple features as a bundle
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.4.3-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.1
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/errors@1.1.4
|
||||
- @backstage/types@1.0.2
|
||||
|
||||
## 0.4.3-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.4.3-next.0",
|
||||
"version": "0.4.3-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.1.34-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli@0.22.2-next.0
|
||||
- @backstage/backend-common@0.18.2-next.1
|
||||
- @backstage/backend-plugin-api@0.3.2-next.1
|
||||
- @backstage/backend-app-api@0.3.2-next.1
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/types@1.0.2
|
||||
- @backstage/plugin-auth-node@0.2.11-next.1
|
||||
|
||||
## 0.1.34-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.1.34-next.0",
|
||||
"version": "0.1.34-next.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.80-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-backend@1.7.2-next.1
|
||||
- @backstage/plugin-tech-insights-backend@0.5.8-next.1
|
||||
- @backstage/plugin-tech-insights-node@0.4.0-next.1
|
||||
- @backstage/plugin-azure-devops-backend@0.3.21-next.1
|
||||
- @backstage/backend-common@0.18.2-next.1
|
||||
- @backstage/plugin-kubernetes-backend@0.9.3-next.1
|
||||
- @backstage/plugin-scaffolder-backend@1.11.0-next.1
|
||||
- @backstage/plugin-playlist-backend@0.2.5-next.1
|
||||
- example-app@0.2.80-next.1
|
||||
- @backstage/backend-tasks@0.4.3-next.1
|
||||
- @backstage/catalog-client@1.3.1-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/integration@1.4.2
|
||||
- @backstage/plugin-adr-backend@0.2.7-next.1
|
||||
- @backstage/plugin-app-backend@0.3.42-next.1
|
||||
- @backstage/plugin-auth-backend@0.17.5-next.1
|
||||
- @backstage/plugin-auth-node@0.2.11-next.1
|
||||
- @backstage/plugin-azure-sites-backend@0.1.4-next.1
|
||||
- @backstage/plugin-badges-backend@0.1.36-next.1
|
||||
- @backstage/plugin-catalog-node@1.3.3-next.1
|
||||
- @backstage/plugin-code-coverage-backend@0.2.8-next.1
|
||||
- @backstage/plugin-events-backend@0.2.3-next.1
|
||||
- @backstage/plugin-events-node@0.2.3-next.1
|
||||
- @backstage/plugin-explore-backend@0.0.4-next.1
|
||||
- @backstage/plugin-graphql-backend@0.1.32-next.1
|
||||
- @backstage/plugin-jenkins-backend@0.1.32-next.1
|
||||
- @backstage/plugin-kafka-backend@0.2.35-next.1
|
||||
- @backstage/plugin-permission-backend@0.5.17-next.1
|
||||
- @backstage/plugin-permission-common@0.7.3
|
||||
- @backstage/plugin-permission-node@0.7.5-next.1
|
||||
- @backstage/plugin-proxy-backend@0.2.36-next.1
|
||||
- @backstage/plugin-rollbar-backend@0.1.39-next.1
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.1
|
||||
- @backstage/plugin-search-backend@1.2.3-next.1
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.1
|
||||
- @backstage/plugin-search-backend-module-pg@0.5.3-next.1
|
||||
- @backstage/plugin-search-backend-node@1.1.3-next.1
|
||||
- @backstage/plugin-search-common@1.2.1
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.1
|
||||
- @backstage/plugin-techdocs-backend@1.5.3-next.1
|
||||
- @backstage/plugin-todo-backend@0.1.39-next.1
|
||||
|
||||
## 0.2.80-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.80-next.0",
|
||||
"version": "0.2.80-next.1",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,8 +2,11 @@ apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: petstore
|
||||
# This is an extra long description
|
||||
description: The Petstore is an example API used to show features of the OpenAPI spec.
|
||||
# This is an extra long description with Markdown
|
||||
description: |
|
||||
[The Petstore](http://petstore.example.com) is an example API used to show features of the OpenAPI spec.
|
||||
- First item
|
||||
- Second item
|
||||
links:
|
||||
- url: https://github.com/swagger-api/swagger-petstore
|
||||
title: GitHub Repo
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.22.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 561df21ea3: The `backstage-cli repo test` command now sets a default Jest `--workerIdleMemoryLimit` of 1GB. If needed to ensure that tests are not run in band, `--maxWorkers=2` is set as well. This is the recommended workaround for dealing with Jest workers leaking memory and eventually hitting the heap limit.
|
||||
- 2815981057: Show module name causing error during build
|
||||
- 66cf22fdc4: Updated dependency `esbuild` to `^0.17.0`.
|
||||
- 6d3abfded1: Switch to inline source maps for test transpilation, simplifying editor setups.
|
||||
- Updated dependencies
|
||||
- @backstage/cli-common@0.1.11
|
||||
- @backstage/config@1.0.6
|
||||
- @backstage/config-loader@1.1.8
|
||||
- @backstage/errors@1.1.4
|
||||
- @backstage/release-manifests@0.0.8
|
||||
- @backstage/types@1.0.2
|
||||
|
||||
## 0.22.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -22,7 +22,6 @@ const { version } = require('../package.json');
|
||||
|
||||
const envOptions = {
|
||||
oldTests: Boolean(process.env.BACKSTAGE_OLD_TESTS),
|
||||
enableSourceMaps: Boolean(process.env.ENABLE_SOURCE_MAPS),
|
||||
};
|
||||
|
||||
const transformIgnorePattern = [
|
||||
@@ -130,7 +129,6 @@ async function getProjectConfig(targetPath, extraConfig) {
|
||||
'\\.(mjs|cjs|js)$': [
|
||||
require.resolve('./jestSwcTransform'),
|
||||
{
|
||||
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
@@ -141,7 +139,6 @@ async function getProjectConfig(targetPath, extraConfig) {
|
||||
'\\.jsx$': [
|
||||
require.resolve('./jestSwcTransform'),
|
||||
{
|
||||
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
@@ -158,7 +155,6 @@ async function getProjectConfig(targetPath, extraConfig) {
|
||||
'\\.ts$': [
|
||||
require.resolve('./jestSwcTransform'),
|
||||
{
|
||||
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
@@ -169,7 +165,6 @@ async function getProjectConfig(targetPath, extraConfig) {
|
||||
'\\.tsx$': [
|
||||
require.resolve('./jestSwcTransform'),
|
||||
{
|
||||
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user