Merge remote-tracking branch 'upstream/master' into airbrake-api
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/config': patch
|
||||
---
|
||||
|
||||
The `ConfigReader#get` method now always returns a deep clone of the configuration data.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
fix: Register plugin to prioritise Component kind for entityRef
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-todo-backend': patch
|
||||
---
|
||||
|
||||
Properly exported all referenced types
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Add catalog permission rules.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
ESLint upgraded to version 8 and all it's plugins updated to newest version.
|
||||
|
||||
If you use any custom plugins for ESLint please check compatibility.
|
||||
|
||||
```diff
|
||||
- "@typescript-eslint/eslint-plugin": "^v4.33.0",
|
||||
- "@typescript-eslint/parser": "^v4.28.3",
|
||||
+ "@typescript-eslint/eslint-plugin": "^5.9.0",
|
||||
+ "@typescript-eslint/parser": "^5.9.0",
|
||||
- "eslint": "^7.30.0",
|
||||
+ "eslint": "^8.6.0",
|
||||
- "eslint-plugin-import": "^2.20.2",
|
||||
- "eslint-plugin-jest": "^24.1.0",
|
||||
- "eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
+ "eslint-plugin-import": "^2.25.4",
|
||||
+ "eslint-plugin-jest": "^25.3.4",
|
||||
+ "eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
- "eslint-plugin-react": "^7.12.4",
|
||||
- "eslint-plugin-react-hooks": "^4.0.0",
|
||||
+ "eslint-plugin-react": "^7.28.0",
|
||||
+ "eslint-plugin-react-hooks": "^4.3.0",
|
||||
```
|
||||
|
||||
Please consult changelogs from packages if you find any problems.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graphql': patch
|
||||
---
|
||||
|
||||
Bump graphql versions
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-ldap': patch
|
||||
---
|
||||
|
||||
Make sure to avoid accidental data sharing / mutation of `set` values
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-permission-node': patch
|
||||
---
|
||||
|
||||
Add helpers for creating PermissionRules with inferred types
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core-plugin-api': minor
|
||||
---
|
||||
|
||||
Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`.
|
||||
|
||||
The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-ldap': patch
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Clean up API report
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Adds two new home components - CompanyLogo and Toolkit.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Switch Webpack minification to use `esbuild` instead of `terser`.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Add permissions to create-app's PluginEnvironment
|
||||
|
||||
`CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/index.ts
|
||||
|
||||
+ import { ServerPermissionClient } from '@backstage/plugin-permission-node';
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
...
|
||||
+ const permissions = ServerPerimssionClient.fromConfig(config, {
|
||||
+ discovery,
|
||||
+ tokenManager,
|
||||
+ });
|
||||
|
||||
root.info(`Created UrlReader ${reader}`);
|
||||
|
||||
return (plugin: string): PluginEnvironment => {
|
||||
...
|
||||
return {
|
||||
logger,
|
||||
cache,
|
||||
database,
|
||||
config,
|
||||
reader,
|
||||
discovery,
|
||||
tokenManager,
|
||||
scheduler,
|
||||
+ permissions,
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/types.ts
|
||||
|
||||
+ import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
|
||||
|
||||
export type PluginEnvironment = {
|
||||
...
|
||||
+ permissions: PermissionAuthorizer;
|
||||
};
|
||||
```
|
||||
|
||||
[`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies:
|
||||
|
||||
```diff
|
||||
// packages/backend/package.json
|
||||
|
||||
+ "@backstage/plugin-permission-common": "...",
|
||||
+ "@backstage/plugin-permission-node": "...",
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
bump `logform` to use fixed version of `color` dependency
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Removed `@backstage/test-utils` dependency.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Add apply-conditions endpoint for evaluating conditional permissions in catalog backend.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': minor
|
||||
---
|
||||
|
||||
Removed previously deprecated `ApiRegistry` export.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`.
|
||||
|
||||
The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Clean up API reports
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/errors': minor
|
||||
---
|
||||
|
||||
Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`.
|
||||
|
||||
Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
Exclude the AWS session token from credential validation, because it's not necessary in this context.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': patch
|
||||
---
|
||||
|
||||
fix React warning because of missing `key` prop
|
||||
@@ -5,7 +5,7 @@ updates:
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '04:00'
|
||||
open-pull-requests-limit: 5
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- dependencies
|
||||
- package-ecosystem: npm
|
||||
@@ -13,6 +13,6 @@ updates:
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '04:00'
|
||||
open-pull-requests-limit: 2
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- dependencies
|
||||
|
||||
@@ -4,6 +4,14 @@ on:
|
||||
paths:
|
||||
- '.github/workflows/chromatic-storybook-test.yml'
|
||||
- 'packages/storybook/**'
|
||||
- 'packages/config/src/**'
|
||||
- 'packages/theme/src/**'
|
||||
- 'packages/types/src/**'
|
||||
- 'packages/errors/src/**'
|
||||
- 'packages/version-bridge/src/**'
|
||||
- 'packages/test-utils/src/**'
|
||||
- 'packages/core-app-api/src/**'
|
||||
- 'packages/core-plugin-api/src/**'
|
||||
- 'packages/core-components/src/**'
|
||||
- '**/*.stories.tsx'
|
||||
|
||||
|
||||
@@ -136,3 +136,6 @@ site
|
||||
|
||||
# e2e tests
|
||||
cypress/cypress/*
|
||||
|
||||
# Possible leftover from build:api-reports
|
||||
tsconfig.tmp.json
|
||||
|
||||
+3
-2
@@ -77,5 +77,6 @@
|
||||
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon), [Gauthier Roebroeck](https://github.com/gauthier-roebroeck-mox) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
|
||||
| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 |
|
||||
| [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. |
|
||||
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
|
||||
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
|
||||
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
|
||||
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
|
||||
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [Rafał Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<mxfile host="Chrome" modified="2021-12-30T23:10:43.723Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" etag="XmQE_awyVPeS9B3bWnM_" version="15.5.6" type="device"><diagram id="M4OCM2KiCGRnt6vHj1W_" name="Page-1">7V3bktq4Fv0aHknhCwYe06Q7kzmdOZ2kp2ZyXk4JW4AntkXZopvO149sZLAt+YKvEiFVU4OFcdtaa2svSXtvj7Sle/jog932M7KgM1In1mGkfRipqqLMDfK/sOXt2DIPj8KGjW9b9KRzwzf7J6SNE9q6ty0YpE7ECDnY3qUbTeR50MSpNuD76DV92ho56b+6AxvINHwzgcO2/mVbeEtb1fnk/MVv0N5s6Z82DPrFCpg/Nj7ae/TvjVRtHf07fu2C+Fr0/GALLPSaaNLuR9rSRwgfP7mHJXTCvo277fi7h5xvT/ftQw9X+cHBgb9bB924/+ur+fXpXg2e/sFjZaodr/MCnD2MHyS6XfwWd1H0kDC8zGSk3b1ubQy/7YAZfvtKSEHatth1yJFCPgLH3njkswPX5LbuXqCPbdLb72kzRuH5a9txlshBPmnxkEeudMc+Dn3C8ArwkGiij/cRIhdi/42cEn+7oF1NqTiNOfaaAHZC27YJTBWNNgJKps3p2ucOJR9on17Qvwud6U1oEf7RQ/rs6Q5GPt6iDfKA84jC3oq69R+I8Ru1HrDHKN3p8GDjvxOfv4eXejelRx8O9MrRwVt84JEH/Dt5kPhVeHj+WXQU/26NPBxjRzg/if5FZ1nvQ3skzSsHmT+et7Z3bH6wnfhGAwx8TB9DP36bOMrlQID2vkn7788v8AG9HVYfPj/O0cvy95+fNto4HjmAv4G44DzK9hCDQkb50AHYfkmPEa2zQ4kJmkOPMxPuz63tseXMkO9JgnDZ0iHq5t5/iR5HaZsC1p+H5fjnf9RP31+8P/bgiwV/fh+rhmAcYAfccg6k+qwjQiiFhLj24YPLndlMLO7EXBaCO7Pqo0keeWbXwh4uXDN1KPYU3XZC+YHdrpn420HfJjcH/fAU29vQX2VFoGtbVkTFjFgMjr96jI4+zM8t5EjNyEaCvgXgfG1GwProB0x8Y5hzuFqfvomFfaGDqa4zMzJT1VmZOeeozM5EpqJoAg0DzUcBKQcBtaILmeqCuZB5Iwmq9DdhkQV27nmDCYf/Pn9Z6v9b2IuvfzyZS//ZmE2+xEN//fGiPaFQVWW+U6epUaLCGPEAXNsJG57BFrmAttIbVJQ+KJXBu9uhRR9STaiMmggXyEifyKQo1uu1anIVhWWsjKnRk6LQJ0MrCs4qoGQTi8x4ocioKTThJxZ89miNp6UDr4GqUkrQqnSZikaXmTB0UavypYYckZYvymArpkW3nVAaO2e/sb3xSDWAG+oHJ3T9tJFcKm7e4FN3ySFHLl7g0GKNSx9PLaBeC7JFnZWvhCizfpdCGo8lXQmXX2g5fXbJhEUgP1S8WdunH5rV9ENSylwOXQTzQzl8mQrDl3oyV87tlqp0GU7mFt12Tdky/hVWUwaWL7xll87kS5FDTHDkLoZ98mivfODbMGAoELzargOiSKKkzU0SAJqkl6DPgfoYj9VCZ56CreLOXLCdeYqFSwVfTbvqzSnTmyM9CtsjvUSGBPWB2tTYRK6LvCszLRbTQspVt5o0zhrHZrpaq+Q+gFEVZQwDPN5j22Et6IZ0BaRnQyPNetA8pEHw4wZyLZAVXsxsryjPGZSXdHgW3QUqEz2zHmJU9IEn22q9NxdlNmMCDBy0GZuOHT65REZjTeHc0nlGM1dXmnGB0cwvRTprNByt06/RxFabjzN+23Hs5gavDBJHYUP1slaMvLW9ucErpa6JI8Dz4YW+j/yb9UqqaBROjhXfCbvH9LobzDVgng4NMy+VLg2zTRToxgfYlmuxQRyQh3fFKrvc8OAjgmu0Rvc+DKCfLJEPGXyFmKGUCxv+Ep3SWXeysz1G2fhwDHY78p8tldGU791XNJoT5aTVr2rpLDQE2IJrsHewXDJHHJT7lLE5sRcMcr0ms160I0oOnmKmxG2p/UnO7mX5luflqaz8RTxOZFaRPxVlQ1y9EaA7AvC7fCgCFN52UTGJYAt24UfSU87bnR+u2OPyUT2dcLR27N1vowvqTQRUbEWkaEFHLeYZXcoRUpyhd7robuxd1LC9buLefonIlMLcPoFDU3IimeqM3ANHvqUJI3zEfmXCiBUpWXjbDWOZwuWuvQMzP6KNMsdtix74pBiZCSInbrvvFPY6acji+i85h6OZ+KGVOROPQesoXZRC1FchpUSIuK4bSXaWxYhHR9m5UQ+kGi6LsfC+6zq5a3VutZKSAjLLM7f0xjYOCAL6+VQVMbaNoVwgJ/a3ZxfI0O0U9/SMkBPiIeSeAhP1pHBWIrnT4TaCnrhdWb7f6ki1lwAVawpnPJNbGDMN8DfgCkkmw1ZCjqsXtdZRxfy+k/eVI7+vMBFL3GlrDncaJ/gNWyfrWrkjmBwsvO+EU7k/EAdAwCetT5EIHAkfojybZhauq0Yot5Klk1OCuprORngL/XGe2vYhMOWKXq6zc1zMzAskW5lTV3llsrtz6hXXE4spIF8WV63Aqm44wNPs/XKgYlmPYg54yGJDrwRmQK3En24YwIuT7ZcCxqABJJct+w5Q9bxwJVa64gmTOhvWg0zdhCp9X5kEUszHGhfQGLhucSJOQYbqK81GEMEmZPF9JwSDLLOwqVY+C+Muq7UyC+MXg2cTCC/a7bjG+Vebe/TFFG5x5nba2GhbsnFpwwZ2X8Saq5yyiU8bXqh4r7Rhsz4uos0VzvLEJw03j7Ir1hQKkMLw4nz/niZIauM5tSOd3Kq2QLAtF+gXbKdltp05gcM61/F3ViBCL0xoOymq3nLaipGvTd7Bi1Hp1TLd6JD3yya76dInu+mlyW5yFqISCOPBKzbMSkvLWfDlBrHcVRvYTamEY+x3haElp6hOB/SK3IlAafG+RMmEq1xjqGhPilR13bhQlw6Zkf4xkbtDHumMaxs4q803+qLD4CpJZUfXrEraQleqWb5A1j58LQCtQirwhoC5Y7skb1KtTkzkedDEYBVfYXJJp3BfB89bwGjldfD8aoycQbARwytlPyd5St84X1FinGEsZ+JwvTrnzLiufdxoDFf1dRIOlmpnBsJuQ8kEZYvhPI2h5EZ09Qklp2ilRFC2GJvXGEpeem6vUKoMlMk1YiLaIsmWAZc8K04jmO5K6oo43qnEq50Q5hEmTanU+j3LgO4Q1ErHVaVfCFk99ilALvJ3W9u8gVgJRN7bzfoFsej9IDcEyxHkzYu6QpD7CHIr1RbzEFtQqv05xZwIVgbL5eOnmyFW9IdDW6Kiyz3VqDVrrJH+m1lD4VRZ7hk2uacVtWaIjWEzepzX58DGTiFkgq3WbLC5tc0Hh63CMq7IsPUzSBrCDZIGg5KYbyYNgxofgGs7YcMz2CIX0Fb6ZxRlJGjexElAlKdexVZUmjkR022RIVQb9ddzbo2zDyeRgffkTg3h3Gnjcq83Ay83cKWygVdNrBvAwNvecrxK4ZX14MMLr5kkBt6oAqa0I0N11z8VdmSIVaoAFCupmdmoSri0HKvufcTlmN64rO/Aw9hVM0y9AoYZ7MLSErk7gO2V7dj4jeGfBMvwydS/SQvyhoGDk3am8Eq9dKdvjAo7YXEHP4IVdJ5QYEcvziOmgjBGLgeBY7hbEln6shH3sCEwbN+tQGCb785Dyv+xbwNvw6ktUi1ct5r15++WpbM+FVb+nnbcfIQBffxxGMrZkuxVSmVv/GKRVCjf4mJajMKIEYQT330MEfkcvfBSu/8X</diagram></mxfile>
|
||||
@@ -0,0 +1,746 @@
|
||||
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1261px" height="642px" viewBox="-0.5 -0.5 1261 642" content="<mxfile><diagram id="M4OCM2KiCGRnt6vHj1W_" name="Page-1">7V1dl5s2E/41vnSO+bR9mXV227SbdpNsT5v35j0yyDYNIB8s73rz6ysw2IAEyHxKjnNOT40MXph5ZuYZaUaMtIV3+CUA280nZEN3pE7sw0j7MFJVZWJMyf/CkbfjyEyfHwfWgWPHJ50Hvjo/YHJlPLp3bLjLnIgRcrGzzQ5ayPehhTNjIAjQa/a0FXKzf3UL1pAa+GoBlx7927HxJh5VZ5PzF79CZ72J/7Rpxl8sgfV9HaC9H/+9kaqton/Hrz2Q/FZ8/m4DbPSaGtLuR9oiQAgfP3mHBXRD2SZiO173UPDt6b4D6GOeC9TjBS/A3cPkjqP7wm+JLKKngeH5k5F297pxMPy6BVb47SvRPhnbYM8lRwr5uMMB+g4XyEUBGfGRT067i/8GDDA8FN6ncnp6giqIPIiDN3LKIQuMt+zha0o58dAmpZZkDMRwWJ9+9ywS8iGWCltCBxf+Zh908/7vL9aXp3t19/QvHiuG1rLggOusffLZhSty83ehsByCx/fxMEbh+SvHdZmypQTJEHexbOdZ4RpM6bLEq3Ul37lOSRPaxELjw/jZswJGAd6gNfKB+4hCaUVi/Rdi/Bb7F7DHKCt0eHDwP6nP38KfemfERx8O8S9HB2/JgU8e8J/0Qeqq8PB8WXSUXLdCPk50R7zCJPoXnWW/Dz0WGV66yPr+vHH84/CD457NCgQ4fgz9+G3qqBADO7QPrFh+f32GD+jtsPzw6XGGXha//fi41saJbwXBGuKS82K0hzooRVQAXYCdl6wXbd/6EoAWwOOMhPvzaHtoOSPkWxogTLR0qHVrH7xEj6O0DQH7r8Ni/ON39eO3F/+PPfhswx/fxqopGAZoh1uNgYzMOgKEUgqIa3cfTOxMp2JhJ8GyENiZ8nuTIvBMrwU9THVN1aHQU3bbKeYHtttm5G8LA4fcHAzCUxx/HV+VJ4GeY9sRFHNkcXe86jE6+jA7j5AjNUcbifZtAGcriyLr5BvTmsHl6vRNkvqUBhh+npmjmapO08wZg2V2RjIVRRPIDTT3AlI6AZUzhBi6YCFk1oiCKv0lLLKonXneYMThz+fPC/1/c2f+5Y8naxE8m9PJ58T11/cX7REFXpb5TjUyXoLDRzwAz3HDgWewQR6IR+MbVBSJIMX0JIM5krK7TrGJcAqRyEQmRrFarVSLyShsc2kaZk+MQp8MzSgYs4CSJRY5f6HIyCk04RMLNnq0xmnpwHOgqpQUlBcuhmhwmQoDF5UXLzXoiLR4UQabMS277RTT2Lr7teOPR6oJvJA/uGHojwfJTyXDa3wSlxx05OIJDi3huPHjqSXQa4G2qNPqmRBl2u9USGNf0hVx+Ymm06eiZzAFcah8sbbPODStGYekpLkMuAgWhwrwYgiDl3o0V87lFl64DEdzy267Jm0Z/wyzKQPTF9a0S2f0pSwgpjByl6h98ugsAxA4cEdBYPfqeC6IKonSNjdJKdAiUoIBQ9XHeqwWhGnkKtv0OS3MU7VgpvjK6EqaBiXNkR4VNhIpEZegPsQ2NbaQ5yH/ykyL1mkp5PitJqtnjWEzXc1VMh/A5NUyhjs83mPHpS3opmkOTU+H1jQdQYs0DXbfb0qupWSFVTPbq5ZnlJYXsXsWPQQqEz03H2JyxsCTbbUuzXmVzVgAAxetx5brhE8ukdHYBpzZOstoZupSMy8wmtmlms4bDYPr9Gs0idUW6xm/bRl2c1OvDBRHoUv18laM/JWzvqlXSl6TVIAXqxcGAQpu1ispo1EYPVbsIOwdGxBvaq6hZmNoNbNa6bJqdggDXQcAO3JNNoij5OFDsUpPNzwEiOg1mqN7HxbQTxYogJR+hchQqokNe4qujf5TtjjpbI9iNgEcg+2W/OdIZTTVa/ecRnOCnLT8Va3MQkMF23AF9i6Wi+aIo+U+aWxB7QWluV6bWS9aESUHTwlSkrHM+iRj9bJ6yfPyVlb2JB6jMqssnoqyIK7eANAdANgiHwoApbddtpnEbgO24UciKfftLghn7HG1V882HK1cZ/vr6IL9JnYx2YpA0QKPms9yvJRBpBiu15h353vnNWyvm7q3n6IypbS3T+DSlIJKpjqee+DKtyxghK/Y5waMWJWSpbfdsJYpnO7auzB3UTwoc9226IVPiplLEBl12323sNdpQxY3fsnpjqbil1YWJB6D7qN0UQtRXxsppUrEdd1Mo7OqRjw6yudGPYBquC7G0vuuG+SuNbjVakrakSzP2sQ3tnbBbhd/Pu0bmdjGUCGQUfvbcwik4Haqe3pGyA31IeSaAlX1pDBmIpnpcBtFT0xRVq+3ulKtJUDFNuCUZXJzc6oB9gJcKchkWEooCPWi7nXE2d93ir5y9PeVNmKJm7YWYKdxg9+w+2RdK3YEo4Ol950KKvcHEgCI8snoU0QCR8KXKE+N3MQ1b4VyK106BVtQ8/FshDcwGBex7QACS67q5Torx+XIvICyVQV1lbVNdndBnXM+sRwC8nVx1Sqs6gYDLM7eLwY4t/Uox4CPbLr0SmAE1Gr86QYBrDrZfiFgDlpActm07wC7npfOxEq3ecKkzoL1IKmbUFvfc4NAinys8QYaA+9bnKpTkGH3lWYeRLCELLnvFGGQJQsztOosjDmt1koWxt4Mnm4gvGi14xrzrzbX6Msh3GLmdlrYaJuyMWFDF3ZfhJqrTNnEhw2rVLxX2NBdHxfB5gqzPPFBw+yj7Ao1pQSktLy4OL5nAZJZeM6sSKeXqm2w21QT9AuW03LLzozCYZ0Z+DvbIEIvbWg7MareetrKNV8bvINvRqXzdbrFLu+nbXbTpW9202lOlN+KQ8qNqATS8eA7Nkwrt5az4ctNxXLv2kAvSqUCY78zDC0FRdUYMCoyE4HKzftSWyZc5RwDpz0pUu3rxlR1pcuM+I+FvC3yiTCuzXHy5Rt9wWFwlqTS3jXPkjbQkyrLF8jah98LQONoBV4TZW5pkRQl1erEQr4PLQyWyS9MLhEK83XwrAmMVl4Hz96NkeEEGyGcq/s5jdP4jfOcFOOsxmokDifVGSPjuna/0Vhd/PMkDF2qnRkIvQwlkypbLOdprEpmRVefqmRsWimRKluszWusSlZ7bq+qVClVpueICWmLKFtOueRZcVaDWVHGoYgRnSqi2knDLMBkIZWZv6cR0J0GtUq/qvSrQpqPfdwhDwXbjWPdlMilRNbbzfpVYtn7QW4arNYgKy/qSoPMR5CbqbbYh9gCU+0vKBZUsFK6XDx+vBkiZzwc2hIVXe5Uo1bWWKP9NzeHwthluWe1yZ1W1MoQG6vN7DGvL1AbnULIpLZa2WBza5sNrjaOaVyR1daPkzSFc5ImpSUx30waFjU+AM9xw4FnsEEeiEfjP6MoI0H7Jk4Eorr1KrGiys6JBG7zHKDa2H+94NYY63ASGXhP4dQULpw23u71ZuDVBq5wGzhvY90ABt72kuNVEq98BB+eeE0lMfBGO2BK6xn4Q78hrGdIWKoAEKvYM7PRLuHSYow/+oiLMb3xtr4Du7GrRph6BQgz6YmlBfK2ADtLx3XwG4U/Cabh061/kxboDaUORtuZwtrqpTt+Y3KshCUCfgRL6D6hnRO9OI+YCsIYeQwNHMvd0pqNXzbiHdZEDZt3S7BzrHdnl/J/HDjAXzP2FuEr1+Wz/uLVsmzXp0LT39OKW4AwiB9/HJZytkR7lUram7xYJFPKN28Oi7YnFplGXCAQhth4lx1NVhEAq9qxBctpe2qmMxFR8yM9Cqnt9LY3IbFKgtqR0SiszkI49d0voff7FL1cVrv/Dw==</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<rect x="0" y="0" width="10" height="10" fill="#ffffff" stroke="none" pointer-events="all"/>
|
||||
<rect x="180" y="500" width="100" height="130" fill="none" stroke="#000000" pointer-events="all"/>
|
||||
<path d="M 160 245 L 253.88 245" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 258.88 245 L 253.88 246.67 L 253.88 243.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 120 230 Q 120 230 120 136.12" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 120 131.12 L 121.67 136.12 L 118.33 136.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 120 260 Q 120 305 143.88 305" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 148.88 305 L 143.88 306.67 L 143.88 303.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 140 230 Q 140 137.5 243.88 137.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 248.88 137.5 L 243.88 139.17 L 243.88 135.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="80" y="230" width="80" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 70px; height: 1px; padding-top: 245px; margin-left: 90px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
app
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="90" y="249" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
app
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 120 390 Q 120 345 143.88 345" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 148.88 345 L 143.88 346.67 L 143.88 343.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 160 405 L 253.88 405" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 258.88 405 L 253.88 406.67 L 253.88 403.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 140 420 Q 140 450 347.5 450 Q 555 450 555 473.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 555 478.88 L 553.33 473.88 L 556.67 473.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="80" y="390" width="80" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 70px; height: 1px; padding-top: 405px; margin-left: 90px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||
backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="90" y="409" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 387.5 230 Q 387.5 205 378.75 205 Q 370 205 370 186.12" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 370 181.12 L 371.67 186.12 L 368.33 186.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 430 245 Q 475 245 475 266.25 Q 475 287.5 513.88 287.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 518.88 287.5 L 513.88 289.17 L 513.88 285.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 430 237.5 Q 585 237.5 585 233.75 Q 585 230 690 230 Q 795 230 795 243.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 795 248.88 L 793.33 243.88 L 796.67 243.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="260" y="230" width="170" height="30" fill="#dae8fc" stroke="#6c8ebf" stroke-width="3" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 160px; height: 1px; padding-top: 245px; margin-left: 270px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="270" y="249" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 387.5 420 Q 387.5 555 493.88 555" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 498.88 555 L 493.88 556.67 L 493.88 553.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 430 412.5 Q 585 412.5 585 416.25 Q 585 420 690 420 Q 795 420 795 406.12" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 795 401.12 L 796.67 406.12 L 793.33 406.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 430 405 Q 475 405 475 383.75 Q 475 362.5 513.88 362.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 518.88 362.5 L 513.88 364.17 L 513.88 360.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<rect x="260" y="390" width="170" height="30" fill="#fff2cc" stroke="#d6b656" stroke-width="3" pointer-events="all"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 160px; height: 1px; padding-top: 405px; margin-left: 270px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-backend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="270" y="409" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-backend
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 500 480 L 500 480 L 720 480 L 720 480" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||
<path d="M 500 480 L 500 630 L 720 630 L 720 480" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 500 480 L 720 480" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="609.5" y="497.5">
|
||||
Backend Libraries
|
||||
</text>
|
||||
</g>
|
||||
<rect x="520" y="510" width="180" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 525px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/backend-common
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="529" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/backend-common
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="520" y="550" width="180" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 565px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/backend-test-utils
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="569" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/backend-test-utils
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="520" y="590" width="180" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 605px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/backend-tasks
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="609" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/backend-tasks
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1030 250 L 1030 250 L 1250 250 L 1250 250" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1030 250 L 1030 520 L 1250 520 L 1250 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1030 250 L 1250 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="1139.5" y="267.5">
|
||||
Common Libraries
|
||||
</text>
|
||||
</g>
|
||||
<rect x="1050" y="440" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 455px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/catalog-client
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="459" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/catalog-client
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1050" y="280" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 295px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/types
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="299" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/types
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1050" y="320" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 335px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/config
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="339" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/config
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1050" y="360" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 375px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/errors
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="379" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/errors
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1050" y="400" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 415px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/catalog-model
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="419" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/catalog-model
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1050" y="480" width="180" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 495px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/integration
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="499" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/integration
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 10 20 L 10 20 L 230 20 L 230 20" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 10 20 L 10 130 L 230 130 L 230 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 10 20 L 230 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="119.5" y="37.5">
|
||||
Frontend App Core
|
||||
</text>
|
||||
</g>
|
||||
<rect x="30" y="50" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 65px; margin-left: 40px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/core-app-api
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="40" y="69" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/core-app-api
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="30" y="90" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 105px; margin-left: 40px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/app-defaults
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="40" y="109" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/app-defaults
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 988 305 Q 1010 305 1010 345 Q 1010 385 1023.88 385" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1028.88 385 L 1023.88 386.67 L 1023.88 383.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 988 305 Q 1010 305 1010 250 Q 1010 195 1023.88 195" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1028.88 195 L 1023.88 196.67 L 1023.88 193.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 990 10 L 985 10 Q 980 10 980 20 L 980 295 Q 980 305 975 305 L 972.5 305 Q 970 305 975 305 L 977.5 305 Q 980 305 980 315 L 980 590 Q 980 600 985 600 L 990 600" fill="none" stroke="#000000" stroke-miterlimit="10" transform="translate(980,0)scale(-1,1)translate(-980,0)" pointer-events="none"/>
|
||||
<path d="M 430 345 Q 475 345 475 353.75 Q 475 362.5 513.88 362.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 518.88 362.5 L 513.88 364.17 L 513.88 360.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 430 352.5 Q 465 352.5 465 435 Q 465 517.5 493.88 517.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 498.88 517.5 L 493.88 519.17 L 493.88 515.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="150" y="330" width="280" height="30" fill="#fff2cc" stroke="#d6b656" stroke-width="3" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 270px; height: 1px; padding-top: 345px; margin-left: 160px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-backend-module-<module-id>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="160" y="349" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-backend-module-<module-id>
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 430 305 Q 475 305 475 296.25 Q 475 287.5 513.88 287.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 518.88 287.5 L 513.88 289.17 L 513.88 285.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 430 297.5 Q 464.08 297.5 464.08 186.12" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 464.08 181.12 L 465.75 186.12 L 462.41 186.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="150" y="290" width="280" height="30" fill="#dae8fc" stroke="#6c8ebf" stroke-width="3" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 270px; height: 1px; padding-top: 305px; margin-left: 160px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-module-<module-id>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="160" y="309" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-module-<module-id>
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1030 160 L 1030 160 L 1250 160 L 1250 160" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1030 160 L 1030 230 L 1250 230 L 1250 160" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1030 160 L 1250 160" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="1139.5" y="177.5">
|
||||
Common Tooling
|
||||
</text>
|
||||
</g>
|
||||
<rect x="1050" y="190" width="180" height="30" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 205px; margin-left: 1060px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/cli
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="1060" y="209" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/cli
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 850 400 Q 850 555 726.12 555" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 721.12 555 L 726.12 553.33 L 726.12 556.67 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 850 250 Q 850 95 736.12 95" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 731.12 95 L 736.12 93.33 L 736.12 96.67 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 740 250 L 740 250 L 960 250 L 960 250" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 740 250 L 740 400 L 960 400 L 960 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 740 250 L 960 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="849.5" y="267.5">
|
||||
External Plugin Libraries
|
||||
</text>
|
||||
</g>
|
||||
<rect x="750" y="280" width="200" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 190px; height: 1px; padding-top: 295px; margin-left: 760px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<other-plugin-id>-react
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="760" y="299" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
plugin-<other-plugin-id>-react
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="750" y="320" width="200" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 190px; height: 1px; padding-top: 335px; margin-left: 760px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<other-plugin-id>-common
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="760" y="339" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
plugin-<other-plugin-id>-common
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="750" y="360" width="200" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 190px; height: 1px; padding-top: 375px; margin-left: 760px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<other-plugin-id>-node
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="760" y="379" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
plugin-<other-plugin-id>-node
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 700 325 Q 700 325 733.88 325" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 738.88 325 L 733.88 326.67 L 733.88 323.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 610 400 Q 610 400 610 473.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 610 478.88 L 608.33 473.88 L 611.67 473.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 610 250 Q 610 250 610 186.12" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 610 181.12 L 611.67 186.12 L 608.33 186.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 520 250 L 520 250 L 700 250 L 700 250" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 520 250 L 520 400 L 700 400 L 700 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 520 250 L 700 250" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="609.5" y="267.5">
|
||||
Plugin Libraries
|
||||
</text>
|
||||
</g>
|
||||
<rect x="530" y="280" width="160" height="30" fill="#dae8fc" stroke="#6c8ebf" stroke-width="3" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 150px; height: 1px; padding-top: 295px; margin-left: 540px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-react
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="540" y="299" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-react
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="530" y="320" width="160" height="30" fill="#d5e8d4" stroke="#82b366" stroke-width="3" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 150px; height: 1px; padding-top: 335px; margin-left: 540px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-common
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="540" y="339" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-common
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="530" y="360" width="160" height="30" fill="#fff2cc" stroke="#d6b656" stroke-width="3" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 150px; height: 1px; padding-top: 375px; margin-left: 540px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; font-style: italic; white-space: normal; word-wrap: normal; ">
|
||||
plugin-<plugin-id>-node
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="540" y="379" fill="#000000" font-family="Helvetica" font-size="12px" font-style="italic">
|
||||
plugin-<plugin-id>-node
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 250 10 L 250 10 L 730 10 L 730 10" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/>
|
||||
<path d="M 250 10 L 250 180 L 730 180 L 730 10" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/>
|
||||
<path d="M 250 10 L 730 10" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/>
|
||||
<path d="M 260 20 L 260 20 L 480 20 L 480 20" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 260 20 L 260 170 L 480 170 L 480 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 260 20 L 480 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="369.5" y="37.5">
|
||||
Frontend Plugin Core
|
||||
</text>
|
||||
</g>
|
||||
<rect x="280" y="50" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 65px; margin-left: 290px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/core-plugin-api
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="290" y="69" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/core-plugin-api
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="280" y="90" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 105px; margin-left: 290px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/test-utils
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="290" y="109" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/test-utils
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="280" y="130" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 145px; margin-left: 290px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/dev-utils
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="290" y="149" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/dev-utils
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 500 20 L 500 20 L 720 20 L 720 20" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 500 20 L 500 170 L 720 170 L 720 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 500 20 L 720 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px">
|
||||
<text x="609.5" y="37.5">
|
||||
Frontend Libraries
|
||||
</text>
|
||||
</g>
|
||||
<rect x="520" y="130" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 145px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/integration-react
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="149" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/integration-react
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="520" y="50" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 65px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/core-components
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="69" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/core-components
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="520" y="90" width="180" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 170px; height: 1px; padding-top: 105px; margin-left: 530px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
@backstage/theme
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="530" y="109" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
@backstage/theme
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="10" y="500" width="160" height="130" fill="none" stroke="#000000" pointer-events="none"/>
|
||||
<rect x="20" y="510" width="20" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<rect x="20" y="570" width="20" height="20" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<rect x="20" y="540" width="20" height="20" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 110px; height: 1px; padding-top: 520px; margin-left: 50px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
Frontend Package
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="524" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
Frontend Package
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 110px; height: 1px; padding-top: 550px; margin-left: 50px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
Isomorphic Package
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="554" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
Isomorphic Package
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 110px; height: 1px; padding-top: 580px; margin-left: 50px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
Backend Package
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="584" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
Backend Package
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="20" y="600" width="20" height="20" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 110px; height: 1px; padding-top: 610px; margin-left: 50px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
CLI Package
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="614" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
CLI Package
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="190" y="540" width="20" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<rect x="190" y="600" width="20" height="20" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<rect x="190" y="570" width="20" height="20" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<rect x="250" y="540" width="20" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/>
|
||||
<path d="M 210 550 Q 210 550 243.88 550" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 248.88 550 L 243.88 551.67 L 243.88 548.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="250" y="600" width="20" height="20" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/>
|
||||
<path d="M 210 610 Q 210 610 243.88 610" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 248.88 610 L 243.88 611.67 L 243.88 608.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="250" y="570" width="20" height="20" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/>
|
||||
<path d="M 210 550 Q 230 550 230 562.5 Q 230 575 243.88 575" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 248.88 575 L 243.88 576.67 L 243.88 573.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 210 605 Q 230 605 230 595 Q 230 585 243.88 585" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 248.88 585 L 243.88 586.67 L 243.88 583.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 210 580 Q 210 580 243.88 580" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 248.88 580 L 243.88 581.67 L 243.88 578.33 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g transform="translate(-0.5 -0.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 90px; height: 1px; padding-top: 520px; margin-left: 190px;">
|
||||
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">
|
||||
Compatibility
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="190" y="524" fill="#000000" font-family="Helvetica" font-size="12px">
|
||||
Compatibility
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 251 589 L 251 570 L 270 589 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" transform="rotate(-180,260.5,579.5)" pointer-events="none"/>
|
||||
<rect x="0" y="630" width="10" height="10" fill="#ffffff" stroke="none" pointer-events="none"/>
|
||||
<rect x="1250" y="630" width="10" height="10" fill="#ffffff" stroke="none" pointer-events="none"/>
|
||||
<rect x="1250" y="0" width="10" height="10" fill="#ffffff" stroke="none" pointer-events="none"/>
|
||||
</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>
|
||||
</a>
|
||||
</switch>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB |
@@ -50,3 +50,41 @@ The Bitbucket provider is a structure with two configuration keys:
|
||||
To add the provider to the frontend, add the `bitbucketAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
|
||||
## Using Bitbucket for sign-in
|
||||
|
||||
In order to use the Bitbucket provider for sign-in, you must configure it with a
|
||||
`signIn.resolver`. See the
|
||||
[Sign-In Resolver documentation](../identity-resolver.md) for more details on
|
||||
how this is done. Note that for the Bitbucket provider, you'll want to use
|
||||
`bitbucket` as the provider ID, and `createBitbucketProvider` for the provider
|
||||
factory.
|
||||
|
||||
The `@backstage/plugin-auth-backend` plugin also comes with two built-in
|
||||
resolves that can be used if desired. The first one is the
|
||||
`bitbucketUsernameSignInResolver`, which identifies users by matching their
|
||||
Bitbucket username to `bitbucket.org/username` annotations of `User` entities in
|
||||
the catalog. Note that you must populate your catalog with matching entities or
|
||||
users will not be able to sign in.
|
||||
|
||||
The second resolver is the `bitbucketUsernameSignInResolver`, which works the
|
||||
same way, but uses the Bitbucket user ID instead, and matches on the
|
||||
`bitbucket.org/user-id` annotation.
|
||||
|
||||
The following is an example of how to use one of the built-in resolvers:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createBitbucketProvider,
|
||||
bitbucketUsernameSignInResolver,
|
||||
} from '@backstage/plugin-auth-backend';
|
||||
|
||||
// ...
|
||||
providerFactories: {
|
||||
bitbucket: createBitbucketProvider({
|
||||
signIn: {
|
||||
resolver: bitbucketUsernameSignInResolver,
|
||||
},
|
||||
}),
|
||||
},
|
||||
```
|
||||
|
||||
@@ -97,3 +97,37 @@ of the `SearchType` component.
|
||||
...
|
||||
</Paper>
|
||||
```
|
||||
|
||||
## How to limit what can be searched in the Software Catalog
|
||||
|
||||
The Software Catalog includes a wealth of information about the components,
|
||||
systems, groups, users, and other aspects of your software ecosystem. However,
|
||||
you may not always want _every_ aspect to appear when a user searches the
|
||||
catalog. Examples include:
|
||||
|
||||
- Entities of kind `Location`, which are often not useful to Backstage users.
|
||||
- Entities of kind `User` or `Group`, if you'd prefer that users and groups be
|
||||
exposed to search in a different way (or not at all).
|
||||
|
||||
It's possible to write your own [Collator](./concepts.md#collators) to control
|
||||
exactly what's available to search, (or a [Decorator](./concepts.md#decorators)
|
||||
to filter things out here and there), but the `DefaultCatalogCollator` that's
|
||||
provided by `@backstage/plugin-catalog-backend` offers some configuration too!
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugins/search.ts
|
||||
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
collator: DefaultCatalogCollator.fromConfig(config, {
|
||||
discovery,
|
||||
tokenManager,
|
||||
+ filter: {
|
||||
+ kind: ['API', 'Component', 'Domain', 'Group', 'System', 'User'],
|
||||
+ },
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
As shown above, you can add a catalog entity filter to narrow down what catalog
|
||||
entities are indexed by the search engine.
|
||||
|
||||
@@ -230,7 +230,7 @@ You can do so by including the following lines in the last step of your
|
||||
|
||||
```Dockerfile
|
||||
RUN apt-get update && apt-get install -y python3 python3-pip
|
||||
RUN pip3 install mkdocs-techdocs-core==0.0.16
|
||||
RUN pip3 install mkdocs-techdocs-core==0.2.2
|
||||
```
|
||||
|
||||
Please be aware that the version requirement could change, you need to check our
|
||||
|
||||
@@ -253,3 +253,73 @@ const LogoFull = () => {
|
||||
return <img src={MyCustomLogoFull} />;
|
||||
};
|
||||
```
|
||||
|
||||
## Custom Homepage
|
||||
|
||||
In addition to a custom theme, a custom logo, you can also customize the
|
||||
homepage of your app. To do that we need to go through a few steps.
|
||||
|
||||
### Setting up the Home Page
|
||||
|
||||
1. Create a Home Page Component that will be used for composition.
|
||||
|
||||
`packages/app/src/components/home/HomePage.tsx`
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
|
||||
export const HomePage = () => {
|
||||
return {
|
||||
/* TODO: Compose a Home Page here */
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
2. Add a route where the homepage will live, presumably `/`.
|
||||
|
||||
`packages/app/src/App.tsx`
|
||||
|
||||
```tsx
|
||||
import { HomepageCompositionRoot } from '@backstage/plugin-home';
|
||||
import { HomePage } from './components/home/HomePage';
|
||||
|
||||
// ...
|
||||
<Route path="/" element={<HomepageCompositionRoot />}>
|
||||
<HomePage />
|
||||
</Route>;
|
||||
// ...
|
||||
```
|
||||
|
||||
### Composing your Home Page
|
||||
|
||||
Composing a Home Page is no different from creating a regular React Component,
|
||||
i.e. the App Integrator is free to include whatever content they like. However,
|
||||
there are components developed with the Home Page in mind. If you are looking
|
||||
for components to use when composing your homepage, you can take a look at the
|
||||
[collection of Homepage components](https://backstage.io/?path=/story/plugins-home-components)
|
||||
in storybook. If you don't find a component that suits your needs but want to
|
||||
contribute, check the
|
||||
[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing).
|
||||
|
||||
!!! tip If you want to use one of the available homepage templates you can find
|
||||
the
|
||||
[templates](https://backstage.io/storybook/?path=/story/plugins-home-templates)
|
||||
in the storybook under the "Home" plugin. And if you would like to contribute a
|
||||
template, please see the
|
||||
[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing)
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import { HomePageCompanyLogo } from '@backstage/plugin-home';
|
||||
|
||||
export const HomePage = () => {
|
||||
return (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<HomePageCompanyLogo className={container} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
@@ -179,13 +179,7 @@ Surrounding the plugin are different package groups which are the different
|
||||
possible interface points of the plugin. Note that not all library package lists
|
||||
are complete as packages have been omitted for brevity.
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
NOTE: The diagram is exported from /docs/assets/architecture-overview/package-architecture.drawio
|
||||
It can be edited using https://www.diagrams.net/
|
||||
Export it as a PNG with 10px margin without transparent background
|
||||
-->
|
||||

|
||||
|
||||
### Overview
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
"start": "yarn workspace example-app start",
|
||||
"start-backend": "yarn workspace example-backend start",
|
||||
"build": "lerna run build",
|
||||
"build:api-reports": "yarn tsc:full && yarn build:api-reports:only",
|
||||
"build:api-reports": "yarn build:api-reports:only --tsc",
|
||||
"build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts",
|
||||
"build:api-docs": "yarn build:api-reports --docs",
|
||||
"tsc": "tsc",
|
||||
@@ -68,7 +68,7 @@
|
||||
"@types/webpack": "^5.28.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"cross-env": "^7.0.0",
|
||||
"concurrently": "^6.0.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"eslint-plugin-notice": "^0.9.10",
|
||||
"fs-extra": "9.1.0",
|
||||
"husky": "^6.0.0",
|
||||
|
||||
@@ -34,9 +34,7 @@ import { Server } from 'http';
|
||||
import * as winston from 'winston';
|
||||
import { Writable } from 'stream';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AwsS3UrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class AwsS3UrlReader implements UrlReader {
|
||||
constructor(
|
||||
integration: AwsS3Integration,
|
||||
@@ -59,7 +57,7 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class AzureUrlReader implements UrlReader {
|
||||
constructor(
|
||||
integration: AzureIntegration,
|
||||
@@ -114,12 +112,12 @@ export interface CacheClient {
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CacheClientOptions = {
|
||||
defaultTtl?: number;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CacheClientSetOptions = {
|
||||
ttl?: number;
|
||||
};
|
||||
@@ -133,18 +131,17 @@ export class CacheManager {
|
||||
): CacheManager;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CacheManagerOptions = {
|
||||
logger?: Logger_2;
|
||||
onError?: (err: Error) => void;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const coloredFormat: winston.Logform.Format;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface ContainerRunner {
|
||||
// (undocumented)
|
||||
runContainer(opts: RunContainerOptions): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -157,7 +154,7 @@ export function createDatabaseClient(
|
||||
overrides?: Partial<Knex.Config>,
|
||||
): Knex<any, unknown[]>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function createRootLogger(
|
||||
options?: winston.LoggerOptions,
|
||||
env?: NodeJS.ProcessEnv,
|
||||
@@ -166,14 +163,14 @@ export function createRootLogger(
|
||||
// @public
|
||||
export function createServiceBuilder(_module: NodeModule): ServiceBuilder;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function createStatusCheckRouter(options: {
|
||||
logger: Logger_2;
|
||||
path?: string;
|
||||
statusCheck?: StatusCheck;
|
||||
}): Promise<express.Router>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class DatabaseManager {
|
||||
forPlugin(pluginId: string): PluginDatabaseManager;
|
||||
static fromConfig(
|
||||
@@ -187,7 +184,7 @@ export type DatabaseManagerOptions = {
|
||||
migrations?: PluginDatabaseManager['migrations'];
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class DockerContainerRunner implements ContainerRunner {
|
||||
constructor(options: { dockerClient: Docker });
|
||||
// (undocumented)
|
||||
@@ -205,7 +202,7 @@ export function errorHandler(
|
||||
options?: ErrorHandlerOptions,
|
||||
): ErrorRequestHandler;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ErrorHandlerOptions = {
|
||||
showStackTraces?: boolean;
|
||||
logger?: Logger_2;
|
||||
@@ -218,13 +215,13 @@ export type FromReadableArrayOptions = Array<{
|
||||
path: string;
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function getRootLogger(): winston.Logger;
|
||||
|
||||
// @public
|
||||
export function getVoidLogger(): winston.Logger;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class Git {
|
||||
// (undocumented)
|
||||
add(options: { dir: string; filepath: string }): Promise<void>;
|
||||
@@ -310,7 +307,7 @@ export class GithubUrlReader implements UrlReader {
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class GitlabUrlReader implements UrlReader {
|
||||
constructor(
|
||||
integration: GitLabIntegration,
|
||||
@@ -398,7 +395,7 @@ export type ReadTreeResponseDirOptions = {
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface ReadTreeResponseFactory {
|
||||
// (undocumented)
|
||||
fromReadableArray(
|
||||
@@ -448,7 +445,7 @@ export type ReadUrlResponse = {
|
||||
// @public
|
||||
export function requestLoggingHandler(logger?: Logger_2): RequestHandler;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type RequestLoggingHandlerFactory = (
|
||||
logger?: Logger_2,
|
||||
) => RequestHandler;
|
||||
@@ -459,7 +456,7 @@ export function resolvePackagePath(name: string, ...paths: string[]): string;
|
||||
// @public
|
||||
export function resolveSafeChildPath(base: string, path: string): string;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type RunContainerOptions = {
|
||||
imageName: string;
|
||||
command?: string | string[];
|
||||
@@ -508,7 +505,7 @@ export class ServerTokenManager implements TokenManager {
|
||||
static noop(): TokenManager;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ServiceBuilder = {
|
||||
loadConfig(config: Config): ServiceBuilder;
|
||||
setPort(port: number): ServiceBuilder;
|
||||
@@ -534,7 +531,7 @@ export type ServiceBuilder = {
|
||||
start(): Promise<Server>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function setRootLogger(newLogger: winston.Logger): void;
|
||||
|
||||
// @public @deprecated
|
||||
@@ -554,7 +551,7 @@ export class SingleHostDiscovery implements PluginEndpointDiscovery {
|
||||
getExternalBaseUrl(pluginId: string): Promise<string>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type StatusCheck = () => Promise<any>;
|
||||
|
||||
// @public
|
||||
@@ -562,7 +559,7 @@ export function statusCheckHandler(
|
||||
options?: StatusCheckHandlerOptions,
|
||||
): Promise<RequestHandler>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface StatusCheckHandlerOptions {
|
||||
statusCheck?: StatusCheck;
|
||||
}
|
||||
@@ -597,7 +594,7 @@ export class UrlReaders {
|
||||
static default(options: UrlReadersOptions): UrlReader;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type UrlReadersOptions = {
|
||||
config: Config;
|
||||
logger: Logger_2;
|
||||
@@ -612,8 +609,4 @@ export function useHotCleanup(
|
||||
|
||||
// @public
|
||||
export function useHotMemoize<T>(_module: NodeModule, valueFactory: () => T): T;
|
||||
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/database/types.d.ts:23:12 - (tsdoc-undefined-tag) The TSDoc tag "@default" is not defined in this configuration
|
||||
```
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"keyv-memcache": "^1.2.5",
|
||||
"knex": "^0.95.1",
|
||||
"lodash": "^4.17.21",
|
||||
"logform": "^2.1.1",
|
||||
"logform": "^2.3.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimist": "^1.2.5",
|
||||
"morgan": "^1.10.0",
|
||||
|
||||
+5
-1
@@ -22,7 +22,11 @@ type CacheClientArgs = {
|
||||
client: Keyv;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link CacheClient.set}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CacheClientSetOptions = {
|
||||
/**
|
||||
* Optional TTL in milliseconds. Defaults to the TTL provided when the client
|
||||
|
||||
+4
-3
@@ -55,8 +55,8 @@ export class CacheManager {
|
||||
private readonly errorHandler: CacheManagerOptions['onError'];
|
||||
|
||||
/**
|
||||
* Creates a new CacheManager instance by reading from the `backend` config
|
||||
* section, specifically the `.cache` key.
|
||||
* Creates a new {@link CacheManager} instance by reading from the `backend`
|
||||
* config section, specifically the `.cache` key.
|
||||
*
|
||||
* @param config - The loaded application configuration.
|
||||
*/
|
||||
@@ -93,7 +93,8 @@ export class CacheManager {
|
||||
/**
|
||||
* Generates a PluginCacheManager for consumption by plugins.
|
||||
*
|
||||
* @param pluginId - The plugin that the cache manager should be created for. Plugin names should be unique.
|
||||
* @param pluginId - The plugin that the cache manager should be created for.
|
||||
* Plugin names should be unique.
|
||||
*/
|
||||
forPlugin(pluginId: string): PluginCacheManager {
|
||||
return {
|
||||
|
||||
+17
-7
@@ -17,7 +17,11 @@
|
||||
import { Logger } from 'winston';
|
||||
import { CacheClient } from './CacheClient';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options given when constructing a {@link CacheClient}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CacheClientOptions = {
|
||||
/**
|
||||
* An optional default TTL (in milliseconds) to be set when getting a client
|
||||
@@ -27,7 +31,11 @@ export type CacheClientOptions = {
|
||||
defaultTtl?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options given when constructing a {@link CacheManager}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CacheManagerOptions = {
|
||||
/**
|
||||
* An optional logger for use by the PluginCacheManager.
|
||||
@@ -42,17 +50,19 @@ export type CacheManagerOptions = {
|
||||
};
|
||||
|
||||
/**
|
||||
* The PluginCacheManager manages access to cache stores that Plugins get.
|
||||
* Manages access to cache stores that plugins get.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginCacheManager = {
|
||||
/**
|
||||
* getClient provides backend plugins cache connections for itself.
|
||||
* Provides backend plugins cache connections for themselves.
|
||||
*
|
||||
* The purpose of this method is to allow plugins to get isolated data
|
||||
* stores so that plugins are discouraged from cache-level integration
|
||||
* and/or cache key collisions.
|
||||
* @remarks
|
||||
*
|
||||
* The purpose of this method is to allow plugins to get isolated data stores
|
||||
* so that plugins are discouraged from cache-level integration and/or cache
|
||||
* key collisions.
|
||||
*/
|
||||
getClient: (options?: CacheClientOptions) => CacheClient;
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ function pluginPath(pluginId: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options object.
|
||||
* Creation options for {@link DatabaseManager}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -46,15 +46,20 @@ export type DatabaseManagerOptions = {
|
||||
migrations?: PluginDatabaseManager['migrations'];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Manages database connections for Backstage backend plugins.
|
||||
*
|
||||
* The database manager allows the user to set connection and client settings on
|
||||
* a per pluginId basis by defining a database config block under
|
||||
* `plugin.<pluginId>` in addition to top level defaults. Optionally, a user may
|
||||
* set `prefix` which is used to prefix generated database names if config is
|
||||
* not provided.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class DatabaseManager {
|
||||
/**
|
||||
* Creates a DatabaseManager from `backend.database` config.
|
||||
*
|
||||
* The database manager allows the user to set connection and client settings on a per pluginId
|
||||
* basis by defining a database config block under `plugin.<pluginId>` in addition to top level
|
||||
* defaults. Optionally, a user may set `prefix` which is used to prefix generated database
|
||||
* names if config is not provided.
|
||||
* Creates a {@link DatabaseManager} from `backend.database` config.
|
||||
*
|
||||
* @param config - The loaded application configuration.
|
||||
* @param options - An optional configuration object.
|
||||
@@ -108,7 +113,7 @@ export class DatabaseManager {
|
||||
* which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is
|
||||
* `schema`, it will fallback to using the default database for the knex instance.
|
||||
*
|
||||
* @param pluginId Lookup the database name for given plugin
|
||||
* @param pluginId - Lookup the database name for given plugin
|
||||
* @returns String representing the plugin's database name
|
||||
*/
|
||||
private getDatabaseName(pluginId: string): string | undefined {
|
||||
@@ -143,12 +148,13 @@ export class DatabaseManager {
|
||||
/**
|
||||
* Provides the client type which should be used for a given plugin.
|
||||
*
|
||||
* The client type is determined by plugin specific config if present. Otherwise the base
|
||||
* client is used as the fallback.
|
||||
* The client type is determined by plugin specific config if present.
|
||||
* Otherwise the base client is used as the fallback.
|
||||
*
|
||||
* @param pluginId Plugin to get the client type for
|
||||
* @returns Object with client type returned as `client` and boolean representing whether
|
||||
* or not the client was overridden as `overridden`
|
||||
* @param pluginId - Plugin to get the client type for
|
||||
* @returns Object with client type returned as `client` and boolean
|
||||
* representing whether or not the client was overridden as
|
||||
* `overridden`
|
||||
*/
|
||||
private getClientType(pluginId: string): {
|
||||
client: string;
|
||||
@@ -169,8 +175,8 @@ export class DatabaseManager {
|
||||
/**
|
||||
* Provides the knexConfig which should be used for a given plugin.
|
||||
*
|
||||
* @param pluginId Plugin to get the knexConfig for
|
||||
* @returns the merged kexConfig value or undefined if it isn't specified
|
||||
* @param pluginId - Plugin to get the knexConfig for
|
||||
* @returns The merged knexConfig value or undefined if it isn't specified
|
||||
*/
|
||||
private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {
|
||||
const pluginConfig = this.config
|
||||
@@ -197,13 +203,15 @@ export class DatabaseManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a Knex connection plugin config by combining base and plugin config.
|
||||
* Provides a Knex connection plugin config by combining base and plugin
|
||||
* config.
|
||||
*
|
||||
* This method provides a baseConfig for a plugin database connector. If the client type
|
||||
* has not been overridden, the global connection config will be included with plugin
|
||||
* specific config as the base. Values from the plugin connection take precedence over the
|
||||
* base. Base database name is omitted for all supported databases excluding SQLite unless
|
||||
* `pluginDivisionMode` is set to `schema`.
|
||||
* This method provides a baseConfig for a plugin database connector. If the
|
||||
* client type has not been overridden, the global connection config will be
|
||||
* included with plugin specific config as the base. Values from the plugin
|
||||
* connection take precedence over the base. Base database name is omitted for
|
||||
* all supported databases excluding SQLite unless `pluginDivisionMode` is set
|
||||
* to `schema`.
|
||||
*/
|
||||
private getConnectionConfig(
|
||||
pluginId: string,
|
||||
@@ -249,9 +257,10 @@ export class DatabaseManager {
|
||||
/**
|
||||
* Provides a Knex database config for a given plugin.
|
||||
*
|
||||
* This method provides a Knex configuration object along with the plugin's client type.
|
||||
* This method provides a Knex configuration object along with the plugin's
|
||||
* client type.
|
||||
*
|
||||
* @param pluginId The plugin that the database config should correspond with
|
||||
* @param pluginId - The plugin that the database config should correspond with
|
||||
*/
|
||||
private getConfigForPlugin(pluginId: string): Knex.Config {
|
||||
const { client } = this.getClientType(pluginId);
|
||||
@@ -264,20 +273,21 @@ export class DatabaseManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a partial Knex.Config database schema override for a given plugin.
|
||||
* Provides a partial `Knex.Config` database schema override for a given
|
||||
* plugin.
|
||||
*
|
||||
* @param pluginId Target plugin to get database schema override
|
||||
* @returns Partial Knex.Config with database schema override
|
||||
* @param pluginId - Target plugin to get database schema override
|
||||
* @returns Partial `Knex.Config` with database schema override
|
||||
*/
|
||||
private getSchemaOverrides(pluginId: string): Knex.Config | undefined {
|
||||
return createSchemaOverride(this.getClientType(pluginId).client, pluginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a partial Knex.Config database name override for a given plugin.
|
||||
* Provides a partial `Knex.Config`• database name override for a given plugin.
|
||||
*
|
||||
* @param pluginId Target plugin to get database name override
|
||||
* @returns Partial Knex.Config with database name override
|
||||
* @param pluginId - Target plugin to get database name override
|
||||
* @returns Partial `Knex.Config` with database name override
|
||||
*/
|
||||
private getDatabaseOverrides(pluginId: string): Knex.Config {
|
||||
const databaseName = this.getDatabaseName(pluginId);
|
||||
@@ -289,8 +299,9 @@ export class DatabaseManager {
|
||||
/**
|
||||
* Provides a scoped Knex client for a plugin as per application config.
|
||||
*
|
||||
* @param pluginId Plugin to get a Knex client for
|
||||
* @returns Promise which resolves to a scoped Knex database client for a plugin
|
||||
* @param pluginId - Plugin to get a Knex client for
|
||||
* @returns Promise which resolves to a scoped Knex database client for a
|
||||
* plugin
|
||||
*/
|
||||
private async getDatabase(pluginId: string): Promise<Knex> {
|
||||
const pluginConfig = new ConfigReader(
|
||||
|
||||
@@ -58,7 +58,7 @@ export function createDatabaseClient(
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for createDatabaseClient
|
||||
* Alias for {@link createDatabaseClient}
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use createDatabaseClient instead
|
||||
@@ -100,7 +100,8 @@ export async function ensureSchemaExists(
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a Knex.Config object with the provided database name for a given client.
|
||||
* Provides a `Knex.Config` object with the provided database name for a given
|
||||
* client.
|
||||
*/
|
||||
export function createNameOverride(
|
||||
client: string,
|
||||
@@ -117,7 +118,8 @@ export function createNameOverride(
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a Knex.Config object with the provided database schema for a given client. Currently only supported by `pg`.
|
||||
* Provides a `Knex.Config` object with the provided database schema for a given
|
||||
* client. Currently only supported by `pg`.
|
||||
*/
|
||||
export function createSchemaOverride(
|
||||
client: string,
|
||||
@@ -156,7 +158,8 @@ export function parseConnectionString(
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a connection config or string into an object which can be passed to Knex.
|
||||
* Normalizes a connection config or string into an object which can be passed
|
||||
* to Knex.
|
||||
*/
|
||||
export function normalizeConnection(
|
||||
connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface PluginDatabaseManager {
|
||||
/**
|
||||
* skip database migrations. Useful if connecting to a read-only database.
|
||||
*
|
||||
* @default false
|
||||
* @defaultValue false
|
||||
*/
|
||||
skip?: boolean;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,11 @@ const coloredTemplate = (info: TransformableInfo) => {
|
||||
return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A logging format that adds coloring to console output.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const coloredFormat = winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.colorize({
|
||||
|
||||
@@ -23,12 +23,29 @@ import { escapeRegExp } from '../util/escapeRegExp';
|
||||
let rootLogger: winston.Logger;
|
||||
let redactionRegExp: RegExp | undefined;
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Gets the current root logger.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function getRootLogger(): winston.Logger {
|
||||
return rootLogger;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Sets a completely custom default "root" logger.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This is the logger instance that will be the foundation for all other logger
|
||||
* instances passed to plugins etc, in a given backend.
|
||||
*
|
||||
* Only use this if you absolutely need to make a completely custom logger.
|
||||
* Normally if you want to make light adaptations to the default logger
|
||||
* behavior, you would instead call {@link createRootLogger}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function setRootLogger(newLogger: winston.Logger) {
|
||||
rootLogger = newLogger;
|
||||
}
|
||||
@@ -67,7 +84,17 @@ function redactLogLine(info: winston.Logform.TransformableInfo) {
|
||||
return info;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Creates a default "root" logger. This also calls {@link setRootLogger} under
|
||||
* the hood.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This is the logger instance that will be the foundation for all other logger
|
||||
* instances passed to plugins etc, in a given backend.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createRootLogger(
|
||||
options: winston.LoggerOptions = {},
|
||||
env = process.env,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import {
|
||||
AuthenticationError,
|
||||
ConflictError,
|
||||
ErrorResponse,
|
||||
ErrorResponseBody,
|
||||
InputError,
|
||||
NotAllowedError,
|
||||
NotFoundError,
|
||||
@@ -28,7 +28,11 @@ import { ErrorRequestHandler, NextFunction, Request, Response } from 'express';
|
||||
import { Logger } from 'winston';
|
||||
import { getRootLogger } from '../logging';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to the {@link errorHandler} middleware.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ErrorHandlerOptions = {
|
||||
/**
|
||||
* Whether error response bodies should show error stack traces or not.
|
||||
@@ -89,7 +93,7 @@ export function errorHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
const body: ErrorResponse = {
|
||||
const body: ErrorResponseBody = {
|
||||
error: serializeError(error, { includeStack: showStackTraces }),
|
||||
request: { method: req.method, url: req.url },
|
||||
response: { statusCode },
|
||||
|
||||
@@ -16,10 +16,19 @@
|
||||
|
||||
import { NextFunction, Request, Response, RequestHandler } from 'express';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A custom status checking function, passed to {@link statusCheckHandler} and
|
||||
* {@link createStatusCheckRouter}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type StatusCheck = () => Promise<any>;
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link statusCheckHandler}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface StatusCheckHandlerOptions {
|
||||
/**
|
||||
* Optional status function which returns a message.
|
||||
|
||||
@@ -94,6 +94,11 @@ const parseURL = (
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for AWS S3 buckets.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class AwsS3UrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
@@ -38,7 +38,11 @@ import {
|
||||
ReadUrlResponse,
|
||||
} from './types';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Implements a {@link UrlReader} for Azure repos.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class AzureUrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
@@ -41,8 +41,8 @@ import {
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* A processor that adds the ability to read files from Bitbucket v1 and v2 APIs, such as
|
||||
* the one exposed by Bitbucket Cloud itself.
|
||||
* Implements a {@link UrlReader} for files from Bitbucket v1 and v2 APIs, such
|
||||
* as the one exposed by Bitbucket Cloud itself.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* A UrlReader that does a plain fetch of the URL.
|
||||
* A {@link UrlReader} that does a plain fetch of the URL.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@ export type GhBlobResponse =
|
||||
RestEndpointMethodTypes['git']['getBlob']['response']['data'];
|
||||
|
||||
/**
|
||||
* A processor that adds the ability to read files from GitHub v3 APIs, such as
|
||||
* Implements a {@link UrlReader} for files through the GitHub v3 APIs, such as
|
||||
* the one exposed by GitHub itself.
|
||||
*
|
||||
* @public
|
||||
|
||||
@@ -39,7 +39,11 @@ import {
|
||||
} from './types';
|
||||
import { trimEnd } from 'lodash';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files on GitLab.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class GitlabUrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
@@ -48,7 +48,11 @@ const parseURL = (
|
||||
};
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files on Google GCS.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class GoogleGcsUrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config, logger }) => {
|
||||
if (!config.has('integrations.googleGcs')) {
|
||||
|
||||
@@ -27,7 +27,11 @@ import { FetchUrlReader } from './FetchUrlReader';
|
||||
import { GoogleGcsUrlReader } from './GoogleGcsUrlReader';
|
||||
import { AwsS3UrlReader } from './AwsS3UrlReader';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Creation options for {@link UrlReaders}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UrlReadersOptions = {
|
||||
/** Root config object */
|
||||
config: Config;
|
||||
@@ -38,13 +42,13 @@ export type UrlReadersOptions = {
|
||||
};
|
||||
|
||||
/**
|
||||
* UrlReaders provide various utilities related to the UrlReader interface.
|
||||
* Helps construct {@link UrlReader}s.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class UrlReaders {
|
||||
/**
|
||||
* Creates a UrlReader without any known types.
|
||||
* Creates a custom {@link UrlReader} wrapper for your own set of factories.
|
||||
*/
|
||||
static create(options: UrlReadersOptions): UrlReader {
|
||||
const { logger, config, factories } = options;
|
||||
@@ -65,7 +69,8 @@ export class UrlReaders {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UrlReader that includes all the default factories from this package.
|
||||
* Creates a {@link UrlReader} wrapper that includes all the default factories
|
||||
* from this package.
|
||||
*
|
||||
* Any additional factories passed will be loaded before the default ones.
|
||||
*/
|
||||
|
||||
@@ -281,7 +281,12 @@ export type FromReadableArrayOptions = Array<{
|
||||
path: string;
|
||||
}>;
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A factory for response factories that handle the unpacking and inspection of
|
||||
* complex responses such as archive data.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ReadTreeResponseFactory {
|
||||
fromTarArchive(
|
||||
options: ReadTreeResponseFactoryOptions,
|
||||
|
||||
@@ -33,7 +33,11 @@ From : https://isomorphic-git.org/docs/en/onAuth with fix for GitHub
|
||||
Azure 'notempty' token
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A convenience wrapper around the `isomorphic-git` library.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class Git {
|
||||
private constructor(
|
||||
private readonly config: {
|
||||
|
||||
@@ -19,9 +19,26 @@ import Router from 'express-promise-router';
|
||||
import express from 'express';
|
||||
import { errorHandler, statusCheckHandler, StatusCheck } from '../middleware';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Creates a default status checking router, that you can add to your express
|
||||
* app.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This adds a `/healthcheck` route (or any other path, if given as an
|
||||
* argument), which your infra can call to see if the service is ready to serve
|
||||
* requests.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export async function createStatusCheckRouter(options: {
|
||||
logger: Logger;
|
||||
/**
|
||||
* The path (including a leading slash) that the health check should be
|
||||
* mounted on.
|
||||
*
|
||||
* @defaultValue '/healthcheck'
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* If not implemented, the default express middleware always returns 200.
|
||||
|
||||
@@ -20,7 +20,11 @@ import { Router, RequestHandler, ErrorRequestHandler } from 'express';
|
||||
import { Server } from 'http';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A helper for building backend service instances.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ServiceBuilder = {
|
||||
/**
|
||||
* Sets the service parameters based on configuration.
|
||||
@@ -119,5 +123,9 @@ export type ServiceBuilder = {
|
||||
start(): Promise<Server>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A factory for request loggers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RequestLoggingHandlerFactory = (logger?: Logger) => RequestHandler;
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
import { Writable } from 'stream';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to the {@link ContainerRunner.runContainer} method.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RunContainerOptions = {
|
||||
imageName: string;
|
||||
command?: string | string[];
|
||||
@@ -28,7 +32,14 @@ export type RunContainerOptions = {
|
||||
pullImage?: boolean;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Handles the running of containers, on behalf of others.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ContainerRunner {
|
||||
/**
|
||||
* Runs a container image to completion.
|
||||
*/
|
||||
runContainer(opts: RunContainerOptions): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,11 @@ export type UserOptions = {
|
||||
User?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A {@link ContainerRunner} for Docker containers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class DockerContainerRunner implements ContainerRunner {
|
||||
private readonly dockerClient: Docker;
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ module.exports = {
|
||||
name: '@material-ui/icons',
|
||||
message: "Please import '@material-ui/icons/<Icon>' instead.",
|
||||
},
|
||||
{
|
||||
name: '@material-ui/icons/', // because this is possible too ._.
|
||||
message: "Please import '@material-ui/icons/<Icon>' instead.",
|
||||
},
|
||||
...require('module').builtinModules,
|
||||
],
|
||||
// Avoid cross-package imports
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
"@svgr/rollup": "5.5.x",
|
||||
"@svgr/webpack": "5.5.x",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^v4.33.0",
|
||||
"@typescript-eslint/parser": "^v4.28.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.9.0",
|
||||
"@typescript-eslint/parser": "^5.9.0",
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"bfj": "^7.0.2",
|
||||
"buffer": "^6.0.3",
|
||||
@@ -61,16 +61,17 @@
|
||||
"commander": "^6.1.0",
|
||||
"css-loader": "^6.5.1",
|
||||
"diff": "^5.0.0",
|
||||
"esbuild": "^0.14.1",
|
||||
"eslint": "^7.30.0",
|
||||
"esbuild": "^0.14.10",
|
||||
"esbuild-loader": "^2.18.0",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-jest": "^24.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^25.3.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-monorepo": "^0.3.2",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"eslint-plugin-react-hooks": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"express": "^4.17.1",
|
||||
"fork-ts-checker-webpack-plugin": "^4.0.5",
|
||||
"fs-extra": "9.1.0",
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { WebpackOptionsNormalized, WebpackPluginInstance } from 'webpack';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import { WebpackOptionsNormalized } from 'webpack';
|
||||
import { BundlingOptions } from './types';
|
||||
import { isParallelDefault } from '../parallel';
|
||||
|
||||
const { ESBuildMinifyPlugin } = require('esbuild-loader');
|
||||
|
||||
export const optimization = (
|
||||
options: BundlingOptions,
|
||||
@@ -26,16 +26,11 @@ export const optimization = (
|
||||
|
||||
return {
|
||||
minimize: !isDev,
|
||||
// Only configure when parallel is explicitly overridden from the default
|
||||
...(!isParallelDefault(options.parallel)
|
||||
? {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: options.parallel,
|
||||
}) as unknown as WebpackPluginInstance,
|
||||
],
|
||||
}
|
||||
: {}),
|
||||
minimizer: [
|
||||
new ESBuildMinifyPlugin({
|
||||
target: 'es2019',
|
||||
}),
|
||||
],
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
automaticNameDelimiter: '-',
|
||||
|
||||
@@ -265,6 +265,19 @@ describe('ConfigReader', () => {
|
||||
withLogCollector(() => config.getOptionalConfigArray('b')),
|
||||
).toMatchObject({ warn: [] });
|
||||
});
|
||||
|
||||
it('should coerce number strings to numbers', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{
|
||||
data: {
|
||||
port: '123',
|
||||
},
|
||||
context: '1',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(config.getNumber('port')).toEqual(123);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConfigReader with fallback', () => {
|
||||
@@ -661,16 +674,50 @@ describe('ConfigReader.get()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('coerces number strings to numbers', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{
|
||||
data: {
|
||||
port: '123',
|
||||
},
|
||||
context: '1',
|
||||
it('should return deep clones of the backing data', () => {
|
||||
const data1 = {
|
||||
foo: {
|
||||
bar: [],
|
||||
baz: {},
|
||||
},
|
||||
};
|
||||
const data2 = {
|
||||
x: {
|
||||
y: {
|
||||
z: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const reader = ConfigReader.fromConfigs([
|
||||
{ data: data1, context: '1' },
|
||||
{ data: data2, context: '2' },
|
||||
]);
|
||||
|
||||
expect(config.getNumber('port')).toEqual(123);
|
||||
reader.get<any>().foo.bar.push(1);
|
||||
reader.get<any>('foo').bar.push(1);
|
||||
reader.get<any>('foo.bar').push(1);
|
||||
reader.get<any>().foo.baz.x = 1;
|
||||
reader.get<any>('foo').baz.x = 1;
|
||||
reader.get<any>('foo.baz').x = 1;
|
||||
reader.get<any>().x.y.z.w = 1;
|
||||
reader.get<any>('x').y.z.w = 1;
|
||||
reader.get<any>('x.y').z.w = 1;
|
||||
reader.get<any>('x.y.z').w = 1;
|
||||
|
||||
const readerSingle = ConfigReader.fromConfigs([
|
||||
{ data: data1, context: '1' },
|
||||
]);
|
||||
|
||||
readerSingle.get<any>().foo.bar.push(1);
|
||||
readerSingle.get<any>('foo').bar.push(1);
|
||||
readerSingle.get<any>('foo.bar').push(1);
|
||||
readerSingle.get<any>().foo.baz.x = 1;
|
||||
readerSingle.get<any>('foo').baz.x = 1;
|
||||
readerSingle.get<any>('foo.baz').x = 1;
|
||||
|
||||
expect(data1.foo.bar).toEqual([]);
|
||||
expect(data1.foo.baz).toEqual({});
|
||||
expect(data2.x.y.z).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -126,7 +126,7 @@ export class ConfigReader implements Config {
|
||||
|
||||
/** {@inheritdoc Config.getOptional} */
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined {
|
||||
const value = this.readValue(key);
|
||||
const value = cloneDeep(this.readValue(key));
|
||||
const fallbackValue = this.fallback?.getOptional<T>(key);
|
||||
|
||||
if (value === undefined) {
|
||||
@@ -153,11 +153,8 @@ export class ConfigReader implements Config {
|
||||
|
||||
// Avoid merging arrays and primitive values, since that's how merging works for other
|
||||
// methods for reading config.
|
||||
return mergeWith(
|
||||
{},
|
||||
{ value: cloneDeep(fallbackValue) },
|
||||
{ value },
|
||||
(into, from) => (!isObject(from) || !isObject(into) ? from : undefined),
|
||||
return mergeWith({}, { value: fallbackValue }, { value }, (into, from) =>
|
||||
!isObject(from) || !isObject(into) ? from : undefined,
|
||||
).value as T;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ import { oktaAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { oneloginAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
import { PendingOAuthRequest } from '@backstage/core-plugin-api';
|
||||
import { PluginOutput } from '@backstage/core-plugin-api';
|
||||
import { ProfileInfo } from '@backstage/core-plugin-api';
|
||||
import { ProfileInfoApi } from '@backstage/core-plugin-api';
|
||||
import { PropsWithChildren } from 'react';
|
||||
@@ -129,21 +128,6 @@ export type ApiProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
constructor(apis: Map<string, unknown>);
|
||||
// Warning: (ae-forgotten-export) The symbol "ApiRegistryBuilder" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
static builder(): ApiRegistryBuilder;
|
||||
// Warning: (ae-forgotten-export) The symbol "ApiImpl" needs to be exported by the entry point index.d.ts
|
||||
static from(apis: ApiImpl[]): ApiRegistry;
|
||||
// (undocumented)
|
||||
get<T>(api: ApiRef<T>): T | undefined;
|
||||
static with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
|
||||
with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class ApiResolver implements ApiHolder {
|
||||
constructor(factories: ApiFactoryHolder);
|
||||
@@ -208,14 +192,19 @@ export type AppOptions = {
|
||||
icons: AppIcons & {
|
||||
[key in string]: IconComponent;
|
||||
};
|
||||
plugins?: (Omit<BackstagePlugin<any, any>, 'output'> & {
|
||||
output(): (
|
||||
| PluginOutput
|
||||
| {
|
||||
type: string;
|
||||
}
|
||||
)[];
|
||||
})[];
|
||||
plugins?: Array<
|
||||
BackstagePlugin<any, any> & {
|
||||
output?(): Array<
|
||||
| {
|
||||
type: 'feature-flag';
|
||||
name: string;
|
||||
}
|
||||
| {
|
||||
type: string;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
components: AppComponents;
|
||||
themes: (Partial<AppTheme> & Omit<AppTheme, 'theme'>)[];
|
||||
configLoader?: AppConfigLoader;
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ApiRef, ApiHolder } from '@backstage/core-plugin-api';
|
||||
|
||||
type ApiImpl<T = unknown> = readonly [ApiRef<T>, T];
|
||||
|
||||
/** @internal */
|
||||
class ApiRegistryBuilder {
|
||||
private apis: [string, unknown][] = [];
|
||||
|
||||
@@ -35,8 +36,7 @@ class ApiRegistryBuilder {
|
||||
/**
|
||||
* A registry for utility APIs.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Will be removed, use {@link @backstage/test-utils#TestApiProvider} or {@link @backstage/test-utils#TestApiRegistry} instead.
|
||||
* @internal
|
||||
*/
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
static builder() {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
export { ApiProvider } from './ApiProvider';
|
||||
export type { ApiProviderProps } from './ApiProvider';
|
||||
export { ApiRegistry } from './ApiRegistry';
|
||||
export { ApiResolver } from './ApiResolver';
|
||||
export { ApiFactoryRegistry } from './ApiFactoryRegistry';
|
||||
export type { ApiFactoryScope } from './ApiFactoryRegistry';
|
||||
|
||||
@@ -316,7 +316,7 @@ describe('Integration Test', () => {
|
||||
plugins: [
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
register: p => p.featureFlags.register('name'),
|
||||
featureFlags: [{ name: 'name' }],
|
||||
}),
|
||||
],
|
||||
components,
|
||||
@@ -384,8 +384,24 @@ describe('Integration Test', () => {
|
||||
name: 'foo',
|
||||
},
|
||||
],
|
||||
register: p => p.featureFlags.register('name'),
|
||||
}),
|
||||
// We still support consuming the old feature flag API for a little while longer
|
||||
{
|
||||
getId() {
|
||||
return 'old-test';
|
||||
},
|
||||
getApis() {
|
||||
return [];
|
||||
},
|
||||
output() {
|
||||
return [
|
||||
{
|
||||
type: 'feature-flag',
|
||||
name: 'old-feature-flag',
|
||||
},
|
||||
];
|
||||
},
|
||||
} as any,
|
||||
],
|
||||
components,
|
||||
configLoader: async () => [],
|
||||
@@ -412,12 +428,12 @@ describe('Integration Test', () => {
|
||||
);
|
||||
|
||||
expect(storageFlags.registerFlag).toHaveBeenCalledWith({
|
||||
name: 'name',
|
||||
name: 'foo',
|
||||
pluginId: 'test',
|
||||
});
|
||||
expect(storageFlags.registerFlag).toHaveBeenCalledWith({
|
||||
name: 'foo',
|
||||
pluginId: 'test',
|
||||
name: 'old-feature-flag',
|
||||
pluginId: 'old-test',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import { Route, Routes } from 'react-router-dom';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
AppThemeSelector,
|
||||
ConfigReader,
|
||||
LocalStorageFeatureFlags,
|
||||
@@ -80,6 +79,13 @@ import {
|
||||
} from './types';
|
||||
import { AppThemeProvider } from './AppThemeProvider';
|
||||
import { defaultConfigLoader } from './defaultConfigLoader';
|
||||
import { ApiRegistry } from '../apis/system/ApiRegistry';
|
||||
|
||||
type CompatiblePlugin =
|
||||
| BackstagePlugin<any, any>
|
||||
| (Omit<BackstagePlugin<any, any>, 'getFeatureFlags'> & {
|
||||
output(): Array<{ type: 'feature-flag'; name: string }>;
|
||||
});
|
||||
|
||||
export function generateBoundRoutes(bindRoutes: AppOptions['bindRoutes']) {
|
||||
const result = new Map<ExternalRouteRef, RouteRef | SubRouteRef>();
|
||||
@@ -149,7 +155,7 @@ function useConfigLoader(
|
||||
if (noConfigNode) {
|
||||
return {
|
||||
node: (
|
||||
<ApiProvider apis={ApiRegistry.from([[appThemeApiRef, appThemeApi]])}>
|
||||
<ApiProvider apis={ApiRegistry.with(appThemeApiRef, appThemeApi)}>
|
||||
<ThemeProvider>{noConfigNode}</ThemeProvider>
|
||||
</ApiProvider>
|
||||
),
|
||||
@@ -183,7 +189,7 @@ export class AppManager implements BackstageApp {
|
||||
|
||||
private readonly apis: Iterable<AnyApiFactory>;
|
||||
private readonly icons: NonNullable<AppOptions['icons']>;
|
||||
private readonly plugins: Set<BackstagePlugin<any, any>>;
|
||||
private readonly plugins: Set<CompatiblePlugin>;
|
||||
private readonly components: AppComponents;
|
||||
private readonly themes: AppTheme[];
|
||||
private readonly configLoader?: AppConfigLoader;
|
||||
@@ -196,9 +202,7 @@ export class AppManager implements BackstageApp {
|
||||
constructor(options: AppOptions) {
|
||||
this.apis = options.apis ?? [];
|
||||
this.icons = options.icons;
|
||||
this.plugins = new Set(
|
||||
(options.plugins as BackstagePlugin<any, any>[]) ?? [],
|
||||
);
|
||||
this.plugins = new Set((options.plugins as CompatiblePlugin[]) ?? []);
|
||||
this.components = options.components;
|
||||
this.themes = options.themes as AppTheme[];
|
||||
this.configLoader = options.configLoader ?? defaultConfigLoader;
|
||||
@@ -208,7 +212,7 @@ export class AppManager implements BackstageApp {
|
||||
}
|
||||
|
||||
getPlugins(): BackstagePlugin<any, any>[] {
|
||||
return Array.from(this.plugins);
|
||||
return Array.from(this.plugins) as BackstagePlugin<any, any>[];
|
||||
}
|
||||
|
||||
getSystemIcon(key: string): IconComponent | undefined {
|
||||
@@ -282,16 +286,11 @@ export class AppManager implements BackstageApp {
|
||||
}
|
||||
} else {
|
||||
for (const output of plugin.output()) {
|
||||
switch (output.type) {
|
||||
case 'feature-flag': {
|
||||
featureFlagsApi.registerFlag({
|
||||
name: output.name,
|
||||
pluginId: plugin.getId(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
if (output.type === 'feature-flag') {
|
||||
featureFlagsApi.registerFlag({
|
||||
name: output.name,
|
||||
pluginId: plugin.getId(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,7 +467,7 @@ export class AppManager implements BackstageApp {
|
||||
return this.apiHolder;
|
||||
}
|
||||
|
||||
private verifyPlugins(plugins: Iterable<BackstagePlugin>) {
|
||||
private verifyPlugins(plugins: Iterable<CompatiblePlugin>) {
|
||||
const pluginIds = new Set<string>();
|
||||
|
||||
for (const plugin of plugins) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
RouteRef,
|
||||
SubRouteRef,
|
||||
ExternalRouteRef,
|
||||
PluginOutput,
|
||||
IdentityApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { AppConfig } from '@backstage/config';
|
||||
@@ -232,9 +231,13 @@ export type AppOptions = {
|
||||
/**
|
||||
* A list of all plugins to include in the app.
|
||||
*/
|
||||
plugins?: (Omit<BackstagePlugin<any, any>, 'output'> & {
|
||||
output(): (PluginOutput | { type: string })[];
|
||||
})[];
|
||||
plugins?: Array<
|
||||
BackstagePlugin<any, any> & {
|
||||
output?(): Array<
|
||||
{ type: 'feature-flag'; name: string } | { type: string }
|
||||
>; // support for old plugins
|
||||
}
|
||||
>;
|
||||
|
||||
/**
|
||||
* Supply components to the app to override the default ones.
|
||||
|
||||
@@ -61,14 +61,14 @@ export function ResponseErrorPanel(props: ErrorPanelProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const { data, cause } = error as ResponseError;
|
||||
const { request, response } = data;
|
||||
const { body, cause } = error as ResponseError;
|
||||
const { request, response } = body;
|
||||
|
||||
const errorString = `${response.statusCode}: ${cause.name}`;
|
||||
const requestString = request && `${request.method} ${request.url}`;
|
||||
const messageString = cause.message.replace(/\\n/g, '\n');
|
||||
const stackString = cause.stack?.replace(/\\n/g, '\n');
|
||||
const jsonString = JSON.stringify(data, undefined, 2);
|
||||
const jsonString = JSON.stringify(body, undefined, 2);
|
||||
|
||||
return (
|
||||
<ErrorPanel
|
||||
|
||||
@@ -241,7 +241,6 @@ export type BackstagePlugin<
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
> = {
|
||||
getId(): string;
|
||||
output(): PluginOutput[];
|
||||
getApis(): Iterable<AnyApiFactory>;
|
||||
getFeatureFlags(): Iterable<PluginFeatureFlagConfig>;
|
||||
provide<T>(extension: Extension<T>): T;
|
||||
@@ -446,12 +445,6 @@ export type FeatureFlag = {
|
||||
pluginId: string;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export type FeatureFlagOutput = {
|
||||
type: 'feature-flag';
|
||||
name: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface FeatureFlagsApi {
|
||||
getRegisteredFlags(): FeatureFlag[];
|
||||
@@ -687,7 +680,6 @@ export type PluginConfig<
|
||||
> = {
|
||||
id: string;
|
||||
apis?: Iterable<AnyApiFactory>;
|
||||
register?(hooks: PluginHooks): void;
|
||||
routes?: Routes;
|
||||
externalRoutes?: ExternalRoutes;
|
||||
featureFlags?: PluginFeatureFlagConfig[];
|
||||
@@ -698,14 +690,6 @@ export type PluginFeatureFlagConfig = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export type PluginHooks = {
|
||||
featureFlags: FeatureFlagsHooks;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export type PluginOutput = FeatureFlagOutput;
|
||||
|
||||
// @public
|
||||
export type ProfileInfo = {
|
||||
email?: string;
|
||||
|
||||
@@ -28,62 +28,7 @@ describe('Plugin Feature Flag', () => {
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
register({ featureFlags }) {
|
||||
featureFlags.register('blob');
|
||||
},
|
||||
}).getFeatureFlags(),
|
||||
).toEqual([{ name: 'blob' }]);
|
||||
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
register({ featureFlags }) {
|
||||
featureFlags.register('blob');
|
||||
},
|
||||
featureFlags: [{ name: 'test' }],
|
||||
}).getFeatureFlags(),
|
||||
).toEqual([{ name: 'test' }, { name: 'blob' }]);
|
||||
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
}).getFeatureFlags(),
|
||||
).toEqual([]);
|
||||
|
||||
/* deprecated tests */
|
||||
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
featureFlags: [{ name: 'test' }],
|
||||
}).output(),
|
||||
).toEqual([{ name: 'test', type: 'feature-flag' }]);
|
||||
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
register({ featureFlags }) {
|
||||
featureFlags.register('blob');
|
||||
},
|
||||
}).output(),
|
||||
).toEqual([{ name: 'blob', type: 'feature-flag' }]);
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
register({ featureFlags }) {
|
||||
featureFlags.register('blob');
|
||||
},
|
||||
featureFlags: [{ name: 'test' }],
|
||||
}).output(),
|
||||
).toEqual([
|
||||
{ name: 'test', type: 'feature-flag' },
|
||||
{ name: 'blob', type: 'feature-flag' },
|
||||
]);
|
||||
|
||||
expect(
|
||||
createPlugin({
|
||||
id: 'test',
|
||||
}).output(),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import {
|
||||
PluginConfig,
|
||||
PluginOutput,
|
||||
BackstagePlugin,
|
||||
Extension,
|
||||
AnyRoutes,
|
||||
@@ -33,8 +32,6 @@ export class PluginImpl<
|
||||
ExternalRoutes extends AnyExternalRoutes,
|
||||
> implements BackstagePlugin<Routes, ExternalRoutes>
|
||||
{
|
||||
private storedOutput?: PluginOutput[];
|
||||
|
||||
constructor(private readonly config: PluginConfig<Routes, ExternalRoutes>) {}
|
||||
|
||||
getId(): string {
|
||||
@@ -46,11 +43,7 @@ export class PluginImpl<
|
||||
}
|
||||
|
||||
getFeatureFlags(): Iterable<PluginFeatureFlagConfig> {
|
||||
const registeredFlags = this.output()
|
||||
.filter(({ type }) => type === 'feature-flag')
|
||||
.map(({ name }) => ({ name }));
|
||||
|
||||
return registeredFlags;
|
||||
return this.config.featureFlags?.slice() ?? [];
|
||||
}
|
||||
|
||||
get routes(): Routes {
|
||||
@@ -61,34 +54,6 @@ export class PluginImpl<
|
||||
return this.config.externalRoutes ?? ({} as ExternalRoutes);
|
||||
}
|
||||
|
||||
output(): PluginOutput[] {
|
||||
if (this.storedOutput) {
|
||||
return this.storedOutput;
|
||||
}
|
||||
const outputs = new Array<PluginOutput>();
|
||||
this.storedOutput = outputs;
|
||||
|
||||
if (this.config.featureFlags) {
|
||||
for (const flag of this.config.featureFlags) {
|
||||
outputs.push({ type: 'feature-flag', name: flag.name });
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.config.register) {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
this.config.register({
|
||||
featureFlags: {
|
||||
register(name) {
|
||||
outputs.push({ type: 'feature-flag', name });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return this.storedOutput;
|
||||
}
|
||||
|
||||
provide<T>(extension: Extension<T>): T {
|
||||
return extension.expose(this);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,7 @@ export type {
|
||||
AnyRoutes,
|
||||
BackstagePlugin,
|
||||
Extension,
|
||||
FeatureFlagOutput,
|
||||
FeatureFlagsHooks,
|
||||
PluginConfig,
|
||||
PluginHooks,
|
||||
PluginOutput,
|
||||
PluginFeatureFlagConfig,
|
||||
} from './types';
|
||||
|
||||
@@ -17,24 +17,6 @@
|
||||
import { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';
|
||||
import { AnyApiFactory } from '../apis/system';
|
||||
|
||||
/**
|
||||
* Replace with using {@link RouteRef}s.
|
||||
* @deprecated will be removed
|
||||
* @public
|
||||
*/
|
||||
export type FeatureFlagOutput = {
|
||||
type: 'feature-flag';
|
||||
name: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link FeatureFlagOutput} type.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link BackstagePlugin.getFeatureFlags} instead.
|
||||
*/
|
||||
export type PluginOutput = FeatureFlagOutput;
|
||||
|
||||
/**
|
||||
* Plugin extension type.
|
||||
*
|
||||
@@ -72,10 +54,6 @@ export type BackstagePlugin<
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
> = {
|
||||
getId(): string;
|
||||
/**
|
||||
* @deprecated use getFeatureFlags instead.
|
||||
* */
|
||||
output(): PluginOutput[];
|
||||
getApis(): Iterable<AnyApiFactory>;
|
||||
/**
|
||||
* Returns all registered feature flags for this plugin.
|
||||
@@ -107,23 +85,11 @@ export type PluginConfig<
|
||||
> = {
|
||||
id: string;
|
||||
apis?: Iterable<AnyApiFactory>;
|
||||
/** @deprecated use featureFlags property instead for defining feature flags */
|
||||
register?(hooks: PluginHooks): void;
|
||||
routes?: Routes;
|
||||
externalRoutes?: ExternalRoutes;
|
||||
featureFlags?: PluginFeatureFlagConfig[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds hooks registered by the plugin.
|
||||
*
|
||||
* @deprecated - feature flags are now registered in plugin config under featureFlags
|
||||
* @public
|
||||
*/
|
||||
export type PluginHooks = {
|
||||
featureFlags: FeatureFlagsHooks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for registering feature flags hooks.
|
||||
*
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
"@backstage/plugin-explore": "*",
|
||||
"@backstage/plugin-github-actions": "*",
|
||||
"@backstage/plugin-lighthouse": "*",
|
||||
"@backstage/plugin-permission-common": "*",
|
||||
"@backstage/plugin-permission-node": "*",
|
||||
"@backstage/plugin-proxy-backend": "*",
|
||||
"@backstage/plugin-rollbar-backend": "*",
|
||||
"@backstage/plugin-scaffolder": "*",
|
||||
|
||||
@@ -57,6 +57,8 @@ import { version as pluginExplore } from '../../../../plugins/explore/package.js
|
||||
import { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json';
|
||||
import { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json';
|
||||
import { version as pluginOrg } from '../../../../plugins/org/package.json';
|
||||
import { version as pluginPermissionCommon } from '../../../../plugins/permission-common/package.json';
|
||||
import { version as pluginPermissionNode } from '../../../../plugins/permission-node/package.json';
|
||||
import { version as pluginProxyBackend } from '../../../../plugins/proxy-backend/package.json';
|
||||
import { version as pluginRollbarBackend } from '../../../../plugins/rollbar-backend/package.json';
|
||||
import { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json';
|
||||
@@ -94,6 +96,8 @@ export const packageVersions = {
|
||||
'@backstage/plugin-github-actions': pluginGithubActions,
|
||||
'@backstage/plugin-lighthouse': pluginLighthouse,
|
||||
'@backstage/plugin-org': pluginOrg,
|
||||
'@backstage/plugin-permission-common': pluginPermissionCommon,
|
||||
'@backstage/plugin-permission-node': pluginPermissionNode,
|
||||
'@backstage/plugin-proxy-backend': pluginProxyBackend,
|
||||
'@backstage/plugin-rollbar-backend': pluginRollbarBackend,
|
||||
'@backstage/plugin-scaffolder': pluginScaffolder,
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"@backstage/plugin-app-backend": "^{{version '@backstage/plugin-app-backend'}}",
|
||||
"@backstage/plugin-auth-backend": "^{{version '@backstage/plugin-auth-backend'}}",
|
||||
"@backstage/plugin-catalog-backend": "^{{version '@backstage/plugin-catalog-backend'}}",
|
||||
"@backstage/plugin-permission-common": "^{{version '@backstage/plugin-permission-common'}}",
|
||||
"@backstage/plugin-permission-node": "^{{version '@backstage/plugin-permission-node'}}",
|
||||
"@backstage/plugin-proxy-backend": "^{{version '@backstage/plugin-proxy-backend'}}",
|
||||
"@backstage/plugin-scaffolder-backend": "^{{version '@backstage/plugin-scaffolder-backend'}}",
|
||||
"@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}",
|
||||
|
||||
@@ -29,6 +29,7 @@ import proxy from './plugins/proxy';
|
||||
import techdocs from './plugins/techdocs';
|
||||
import search from './plugins/search';
|
||||
import { PluginEnvironment } from './types';
|
||||
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
const root = getRootLogger();
|
||||
@@ -38,6 +39,10 @@ function makeCreateEnv(config: Config) {
|
||||
const databaseManager = DatabaseManager.fromConfig(config);
|
||||
const tokenManager = ServerTokenManager.noop();
|
||||
const taskScheduler = TaskScheduler.fromConfig(config);
|
||||
const permissions = ServerPermissionClient.fromConfig(config, {
|
||||
discovery,
|
||||
tokenManager,
|
||||
});
|
||||
|
||||
root.info(`Created UrlReader ${reader}`);
|
||||
|
||||
@@ -55,6 +60,7 @@ function makeCreateEnv(config: Config) {
|
||||
discovery,
|
||||
tokenManager,
|
||||
scheduler,
|
||||
permissions,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
UrlReader,
|
||||
} from '@backstage/backend-common';
|
||||
import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
|
||||
|
||||
export type PluginEnvironment = {
|
||||
logger: Logger;
|
||||
@@ -18,4 +19,5 @@ export type PluginEnvironment = {
|
||||
discovery: PluginEndpointDiscovery;
|
||||
tokenManager: TokenManager;
|
||||
scheduler: PluginTaskScheduler;
|
||||
permissions: PermissionAuthorizer;
|
||||
};
|
||||
|
||||
@@ -33,9 +33,6 @@ export type ErrorLike = {
|
||||
[unknownKeys: string]: unknown;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export type ErrorResponse = ErrorResponseBody;
|
||||
|
||||
// @public
|
||||
export type ErrorResponseBody = {
|
||||
error: SerializedError;
|
||||
@@ -68,9 +65,6 @@ export class NotFoundError extends CustomErrorBase {}
|
||||
// @public
|
||||
export class NotModifiedError extends CustomErrorBase {}
|
||||
|
||||
// @public @deprecated
|
||||
export function parseErrorResponse(response: Response): Promise<ErrorResponse>;
|
||||
|
||||
// @public
|
||||
export function parseErrorResponseBody(
|
||||
response: Response,
|
||||
@@ -78,17 +72,8 @@ export function parseErrorResponseBody(
|
||||
|
||||
// @public
|
||||
export class ResponseError extends Error {
|
||||
// @deprecated
|
||||
constructor(props: {
|
||||
message: string;
|
||||
response: Response;
|
||||
data: ErrorResponseBody;
|
||||
cause: Error;
|
||||
});
|
||||
readonly body: ErrorResponseBody;
|
||||
readonly cause: Error;
|
||||
// @deprecated
|
||||
get data(): ErrorResponseBody;
|
||||
static fromResponse(response: Response): Promise<ResponseError>;
|
||||
readonly response: Response;
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ErrorResponse } from '../serialization';
|
||||
import { ErrorResponseBody } from '../serialization';
|
||||
import { ResponseError } from './ResponseError';
|
||||
|
||||
describe('ResponseError', () => {
|
||||
it('constructs itself from a response', async () => {
|
||||
const body: ErrorResponse = {
|
||||
const body: ErrorResponseBody = {
|
||||
error: { name: 'Fours', message: 'Expected fives', stack: 'lines' },
|
||||
request: { method: 'GET', url: '/' },
|
||||
response: { statusCode: 444 },
|
||||
|
||||
@@ -75,10 +75,7 @@ export class ResponseError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated will be removed.
|
||||
**/
|
||||
constructor(props: {
|
||||
private constructor(props: {
|
||||
message: string;
|
||||
response: Response;
|
||||
data: ErrorResponseBody;
|
||||
@@ -90,13 +87,4 @@ export class ResponseError extends Error {
|
||||
this.body = props.data;
|
||||
this.cause = props.cause;
|
||||
}
|
||||
/**
|
||||
* The parsed JSON error body, as sent by the server.
|
||||
* @deprecated use body instead.
|
||||
*/
|
||||
get data(): ErrorResponseBody {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('ErrorResponse.data is deprecated, use .body instead.');
|
||||
return this.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
|
||||
export { deserializeError, serializeError, stringifyError } from './error';
|
||||
export type { SerializedError } from './error';
|
||||
export { parseErrorResponse, parseErrorResponseBody } from './response';
|
||||
export type { ErrorResponse, ErrorResponseBody } from './response';
|
||||
export { parseErrorResponseBody } from './response';
|
||||
export type { ErrorResponseBody } from './response';
|
||||
|
||||
@@ -16,14 +16,6 @@
|
||||
|
||||
import { SerializedError } from './error';
|
||||
|
||||
/**
|
||||
* A standard shape of JSON data returned as the body of backend errors.
|
||||
*
|
||||
* @public
|
||||
* @deprecated - Use {@link ErrorResponseBody} instead.
|
||||
*/
|
||||
export type ErrorResponse = ErrorResponseBody;
|
||||
|
||||
/**
|
||||
* A standard shape of JSON data returned as the body of backend errors.
|
||||
*
|
||||
@@ -48,25 +40,6 @@ export type ErrorResponseBody = {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to construct an ErrorResponse out of a failed server request.
|
||||
* Assumes that the response has already been checked to be not ok. This
|
||||
* function consumes the body of the response, and assumes that it hasn't
|
||||
* been consumed before.
|
||||
*
|
||||
* The code is forgiving, and constructs a useful synthetic body as best it can
|
||||
* if the response body wasn't on the expected form.
|
||||
*
|
||||
* @public
|
||||
* @param response - The response of a failed request
|
||||
* @deprecated - Use {@link parseErrorResponseBody} instead.
|
||||
*/
|
||||
export async function parseErrorResponse(
|
||||
response: Response,
|
||||
): Promise<ErrorResponse> {
|
||||
return parseErrorResponseBody(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to construct an ErrorResponseBody out of a failed server request.
|
||||
* Assumes that the response has already been checked to be not ok. This
|
||||
|
||||
@@ -8,6 +8,7 @@ const BACKSTAGE_CORE_STORIES = [
|
||||
'packages/core-components',
|
||||
'plugins/org',
|
||||
'plugins/search',
|
||||
'plugins/home',
|
||||
];
|
||||
|
||||
module.exports = ({ args }) => {
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/theme": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
|
||||
@@ -8,10 +8,13 @@ import { AnalyticsEvent } from '@backstage/core-plugin-api';
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ConfigApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApiError } from '@backstage/core-plugin-api';
|
||||
import { ErrorApiErrorContext } from '@backstage/core-plugin-api';
|
||||
import { ExternalRouteRef } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { ReactElement } from 'react';
|
||||
@@ -52,6 +55,43 @@ export class MockAnalyticsApi implements AnalyticsApi {
|
||||
// @public
|
||||
export function mockBreakpoint(options: { matches: boolean }): void;
|
||||
|
||||
// @public
|
||||
export class MockConfigApi implements ConfigApi {
|
||||
constructor(data: JsonObject);
|
||||
// (undocumented)
|
||||
get<T = JsonValue>(key?: string): T;
|
||||
// (undocumented)
|
||||
getBoolean(key: string): boolean;
|
||||
// (undocumented)
|
||||
getConfig(key: string): Config;
|
||||
// (undocumented)
|
||||
getConfigArray(key: string): Config[];
|
||||
// (undocumented)
|
||||
getNumber(key: string): number;
|
||||
// (undocumented)
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined;
|
||||
// (undocumented)
|
||||
getOptionalBoolean(key: string): boolean | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfig(key: string): Config | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfigArray(key: string): Config[] | undefined;
|
||||
// (undocumented)
|
||||
getOptionalNumber(key: string): number | undefined;
|
||||
// (undocumented)
|
||||
getOptionalString(key: string): string | undefined;
|
||||
// (undocumented)
|
||||
getOptionalStringArray(key: string): string[] | undefined;
|
||||
// (undocumented)
|
||||
getString(key: string): string;
|
||||
// (undocumented)
|
||||
getStringArray(key: string): string[];
|
||||
// (undocumented)
|
||||
has(key: string): boolean;
|
||||
// (undocumented)
|
||||
keys(): string[];
|
||||
}
|
||||
|
||||
// @public
|
||||
export class MockErrorApi implements ErrorApi {
|
||||
constructor(options?: MockErrorApiOptions);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2022 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 { MockConfigApi } from './MockConfigApi';
|
||||
|
||||
describe('MockConfigApi', () => {
|
||||
it('is able to read some basic config', () => {
|
||||
const mock = new MockConfigApi({
|
||||
app: {
|
||||
title: 'Hello',
|
||||
},
|
||||
x: 1,
|
||||
y: false,
|
||||
z: [{ a: 3 }],
|
||||
});
|
||||
|
||||
expect(mock.getString('app.title')).toEqual('Hello');
|
||||
expect(mock.getNumber('x')).toEqual(1);
|
||||
expect(mock.getBoolean('y')).toEqual(false);
|
||||
expect(mock.getConfigArray('z')[0].getOptionalNumber('a')).toEqual(3);
|
||||
|
||||
expect(() => mock.getString('x')).toThrow(
|
||||
"Invalid type in config for key 'x' in 'mock-config', got number, wanted string",
|
||||
);
|
||||
expect(() => mock.getString('missing')).toThrow(
|
||||
"Missing required config value at 'missing'",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2022 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 { Config, ConfigReader } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { ConfigApi } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* MockConfigApi is a thin wrapper around {@link @backstage/config#ConfigReader}
|
||||
* that can be used to mock configuration using a plain object.
|
||||
*
|
||||
* @public
|
||||
* @example
|
||||
* ```tsx
|
||||
* const mockConfig = new MockConfigApi({
|
||||
* app: { baseUrl: 'https://example.com' },
|
||||
* });
|
||||
*
|
||||
* const rendered = await renderInTestApp(
|
||||
* <TestApiProvider apis={[[configApiRef, mockConfig]]}>
|
||||
* <MyTestedComponent />
|
||||
* </TestApiProvider>,
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export class MockConfigApi implements ConfigApi {
|
||||
private readonly config: ConfigReader;
|
||||
|
||||
// NOTE: not extending in order to avoid inheriting the static `.fromConfigs`
|
||||
constructor(data: JsonObject) {
|
||||
this.config = new ConfigReader(data);
|
||||
}
|
||||
|
||||
/** {@inheritdoc @backstage/config#Config.has} */
|
||||
has(key: string): boolean {
|
||||
return this.config.has(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.keys} */
|
||||
keys(): string[] {
|
||||
return this.config.keys();
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.get} */
|
||||
get<T = JsonValue>(key?: string): T {
|
||||
return this.config.get(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptional} */
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined {
|
||||
return this.config.getOptional(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getConfig} */
|
||||
getConfig(key: string): Config {
|
||||
return this.config.getConfig(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalConfig} */
|
||||
getOptionalConfig(key: string): Config | undefined {
|
||||
return this.config.getOptionalConfig(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getConfigArray} */
|
||||
getConfigArray(key: string): Config[] {
|
||||
return this.config.getConfigArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalConfigArray} */
|
||||
getOptionalConfigArray(key: string): Config[] | undefined {
|
||||
return this.config.getOptionalConfigArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getNumber} */
|
||||
getNumber(key: string): number {
|
||||
return this.config.getNumber(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalNumber} */
|
||||
getOptionalNumber(key: string): number | undefined {
|
||||
return this.config.getOptionalNumber(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getBoolean} */
|
||||
getBoolean(key: string): boolean {
|
||||
return this.config.getBoolean(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalBoolean} */
|
||||
getOptionalBoolean(key: string): boolean | undefined {
|
||||
return this.config.getOptionalBoolean(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getString} */
|
||||
getString(key: string): string {
|
||||
return this.config.getString(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalString} */
|
||||
getOptionalString(key: string): string | undefined {
|
||||
return this.config.getOptionalString(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getStringArray} */
|
||||
getStringArray(key: string): string[] {
|
||||
return this.config.getStringArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalStringArray} */
|
||||
getOptionalStringArray(key: string): string[] | undefined {
|
||||
return this.config.getOptionalStringArray(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export { MockConfigApi } from './MockConfigApi';
|
||||
@@ -15,5 +15,6 @@
|
||||
*/
|
||||
|
||||
export * from './AnalyticsApi';
|
||||
export * from './ConfigApi';
|
||||
export * from './ErrorApi';
|
||||
export * from './StorageApi';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user