Merge branch 'master' of github.com:backstage/backstage into readersprocessorstasks
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.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': minor
|
||||
---
|
||||
|
||||
fixes api auth in tech-insights plugin
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-plugin-api': minor
|
||||
---
|
||||
|
||||
Removed the deprecated `OldIconComponent` type.
|
||||
@@ -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
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Uptake changes to the GitHub Credentials Provider interface.
|
||||
@@ -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,25 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/create-app': patch
|
||||
'@backstage/integration': patch
|
||||
'@backstage/techdocs-common': patch
|
||||
'@backstage/plugin-apache-airflow': patch
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
'@backstage/plugin-azure-devops': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
'@backstage/plugin-code-coverage': patch
|
||||
'@backstage/plugin-code-coverage-backend': patch
|
||||
'@backstage/plugin-cost-insights': patch
|
||||
'@backstage/plugin-fossa': patch
|
||||
'@backstage/plugin-jenkins': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/plugin-search-backend-node': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
---
|
||||
|
||||
Cleaned up API exports
|
||||
@@ -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,7 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-pagerduty': patch
|
||||
'@backstage/plugin-splunk-on-call': patch
|
||||
---
|
||||
|
||||
Clean up emptystate.svg image, removing wrong white artifact from the background
|
||||
@@ -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,7 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored.
|
||||
|
||||
Deprecated the `SamlSession` and `GithubSession` types.
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@backstage/integration': minor
|
||||
---
|
||||
|
||||
Create an interface for the GitHub credentials provider in order to support providing implementations.
|
||||
|
||||
We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`.
|
||||
|
||||
`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials.
|
||||
|
||||
In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers.
|
||||
|
||||
If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`.
|
||||
@@ -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,6 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups.
|
||||
@@ -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,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Bump `testcontainers` dependency to version `8.1.2`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-airbrake': minor
|
||||
---
|
||||
|
||||
A plugin for Airbrake (https://airbrake.io/) has been created
|
||||
@@ -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,6 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
'@backstage/core-plugin-api': patch
|
||||
---
|
||||
|
||||
Removed direct and transitive MUI dependencies.
|
||||
@@ -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
|
||||
@@ -25,12 +25,6 @@ module.exports = {
|
||||
{
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
templateFile: path.resolve(__dirname, './scripts/copyright-header.txt'),
|
||||
templateVars: {
|
||||
NAME: 'The Backstage Authors',
|
||||
},
|
||||
varRegexps: {
|
||||
NAME: /(The Backstage Authors)|(Spotify AB)/,
|
||||
},
|
||||
onNonMatchingHeader: 'replace',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -43,3 +43,4 @@
|
||||
/.changeset/techdocs-* @backstage/techdocs-core
|
||||
/cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-core
|
||||
/plugins/apache-airflow @backstage/reviewers @cmpadden
|
||||
/plugins/newrelic-dashboard @backstage/reviewers @mufaddal7
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
abc
|
||||
accessors
|
||||
Airbrake
|
||||
Anddddd
|
||||
Apdex
|
||||
api
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -124,6 +124,9 @@ jobs:
|
||||
- name: check api reports and generate API reference
|
||||
run: yarn build:api-reports:only --ci --docs
|
||||
|
||||
- name: verify changesets
|
||||
run: node scripts/verify-changesets.js
|
||||
|
||||
- name: verify doc links
|
||||
run: node scripts/verify-links.js
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
for your contributions.
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 7
|
||||
exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc'
|
||||
exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc,will-fix'
|
||||
stale-issue-label: stale
|
||||
stale-pr-message: >
|
||||
This PR has been automatically marked as stale because it has not had
|
||||
@@ -25,6 +25,6 @@ jobs:
|
||||
If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution!
|
||||
days-before-pr-stale: 7
|
||||
days-before-pr-close: 5
|
||||
exempt-pr-labels: reviewer-approved,awaiting-review
|
||||
exempt-pr-labels: reviewer-approved,awaiting-review,will-fix
|
||||
stale-pr-label: stale
|
||||
operations-per-run: 100
|
||||
|
||||
@@ -136,3 +136,6 @@ site
|
||||
|
||||
# e2e tests
|
||||
cypress/cypress/*
|
||||
|
||||
# Possible leftover from build:api-reports
|
||||
tsconfig.tmp.json
|
||||
|
||||
@@ -77,3 +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. |
|
||||
| [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 |
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||
> 🎄 The maintainers will be taking a break over the holidays from week beginning 20th Dec. The Repository and Discord may be quieter than usual. We will be back next year, rested and restored, on Jan. 3. 🎄
|
||||
|
||||
> 🎅 Happy holidays and a Happy New Year to all, and especially those that have made this year special for Backstage! 🎅
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.cncf.io/projects)
|
||||
[](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22)
|
||||
|
||||
@@ -129,8 +129,12 @@ function msUntilExpiry(token: string): number {
|
||||
|
||||
// Calls the specified url regularly using an auth token to set a token cookie
|
||||
// to authorize regular HTTP requests when loading techdocs
|
||||
async function setTokenCookie(url: string, getIdToken: () => Promise<string>) {
|
||||
const token = await getIdToken();
|
||||
async function setTokenCookie(url: string, identityApi: IdentityApi) {
|
||||
const { token } = await identityApi.getCredentials();
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch(url, {
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
@@ -138,11 +142,12 @@ async function setTokenCookie(url: string, getIdToken: () => Promise<string>) {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
// Call this function again a few minutes before the token expires
|
||||
const ms = msUntilExpiry(token) - 4 * 60 * 1000;
|
||||
setTimeout(
|
||||
() => {
|
||||
setTokenCookie(url, getIdToken);
|
||||
setTokenCookie(url, identityApi);
|
||||
},
|
||||
ms > 0 ? ms : 10000,
|
||||
);
|
||||
@@ -160,16 +165,13 @@ const app = createApp({
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
onResult={async result => {
|
||||
// When logged in, set a token cookie
|
||||
if (typeof result.getIdToken !== 'undefined') {
|
||||
setTokenCookie(
|
||||
await discoveryApi.getBaseUrl('cookie'),
|
||||
result.getIdToken,
|
||||
);
|
||||
}
|
||||
// Forward results
|
||||
props.onResult(result);
|
||||
onSignInSuccess={async (identityApi: IdentityApi) => {
|
||||
setTokenCookie(
|
||||
await discoveryApi.getBaseUrl('cookie'),
|
||||
identityApi,
|
||||
);
|
||||
|
||||
props.onSignInSuccess(identityApi);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ ExampleFetchComponent.tsx reference
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
* Copyright 2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
* Copyright 2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
* Copyright 2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
* Copyright 2021 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.
|
||||
|
||||
@@ -35,9 +35,11 @@ We follow this structure for plugin packages (where `x` is the plugin name, for
|
||||
example `catalog` or `techdocs`):
|
||||
|
||||
- `x`: Contains the main frontend code of the plugin.
|
||||
- `x-module-<name>`: Contains optional modules related to the frontend plugin
|
||||
package.
|
||||
- `x-backend`: Contains the main backend code of the plugin.
|
||||
- `x-backend-module-<name>`: Contains optional modules related to the backend
|
||||
plugin.
|
||||
plugin package.
|
||||
- `x-react`: Contains shared widgets, hooks and similar that both the plugin
|
||||
itself (`x`) and third-party frontend plugins can depend on.
|
||||
- `x-node`: Contains utilities for backends that both the plugin backend itself
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
id: adrs-adr013
|
||||
title: 'ADR013: Proper use of HTTP fetching libraries'
|
||||
# prettier-ignore
|
||||
description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, node-fetch, and cross-fetch for data fetching.
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
Using multiple HTTP packages for data fetching increases the complexity and the
|
||||
support burden of keeping said package up to date.
|
||||
|
||||
## Decision
|
||||
|
||||
Backend (node) packages should use the `node-fetch` package for HTTP data
|
||||
fetching. Example:
|
||||
|
||||
```ts
|
||||
import fetch from 'node-fetch';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
|
||||
const response = await fetch('https://example.com/api/v1/users.json');
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
const users = await response.json();
|
||||
```
|
||||
|
||||
Frontend plugins and packages should prefer to use the
|
||||
[`fetchApiRef`](https://backstage.io/docs/reference/core-plugin-api.fetchapiref).
|
||||
It uses `cross-fetch` internally. Example:
|
||||
|
||||
```ts
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
const { fetch } = useApi(fetchApiRef);
|
||||
|
||||
const response = await fetch('https://example.com/api/v1/users.json');
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
const users = await response.json();
|
||||
```
|
||||
|
||||
Isomorphic packages should have a dependency on the `cross-fetch` package for
|
||||
mocking and type definitions. Preferably, classes and functions in isomorphic
|
||||
packages should accept an argument of type `typeof fetch` to let callers supply
|
||||
their preferred implementation of `fetch`. This lets them adorn the calls with
|
||||
auth or other information, and track metrics etc, in a cross-platform way.
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import crossFetch from 'cross-fetch';
|
||||
|
||||
export class MyClient {
|
||||
private readonly fetch: typeof crossFetch;
|
||||
|
||||
constructor(options: { fetch?: typeof crossFetch }) {
|
||||
this.fetch = options.fetch || crossFetch;
|
||||
}
|
||||
|
||||
async users() {
|
||||
return await this.fetch('https://example.com/api/v1/users.json');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
We will gradually transition away from third party packages such as `axios`,
|
||||
`got` and others. Once we have transitioned to `node-fetch` we will add lint
|
||||
rules to enforce this decision.
|
||||
@@ -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 |
@@ -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,
|
||||
},
|
||||
}),
|
||||
},
|
||||
```
|
||||
|
||||
@@ -39,6 +39,7 @@ kubernetes:
|
||||
region: 'europe-west1'
|
||||
skipTLSVerify: true
|
||||
skipMetricsLookup: true
|
||||
exposeDashboard: true
|
||||
```
|
||||
|
||||
### `serviceLocatorMethod`
|
||||
@@ -113,9 +114,13 @@ kubectl -n <NAMESPACE> get secret $(kubectl -n <NAMESPACE> get sa <SERVICE_ACCOU
|
||||
Specifies the link to the Kubernetes dashboard managing this cluster.
|
||||
|
||||
Note that you should specify the app used for the dashboard using the
|
||||
**dashboardApp property**, in order to properly format links to kubernetes
|
||||
`dashboardApp` property, in order to properly format links to kubernetes
|
||||
resources, otherwise it will assume that you're running the standard one.
|
||||
|
||||
Note also that this attribute is optional for some kinds of dashboards, such as
|
||||
GKE, which requires additional parameters specified in the `dashboardParameters`
|
||||
option.
|
||||
|
||||
##### `clusters.\*.dashboardApp` (optional)
|
||||
|
||||
Specifies the app that provides the Kubernetes dashboard.
|
||||
@@ -124,11 +129,14 @@ This will be used for formatting links to kubernetes objects inside the
|
||||
dashboard.
|
||||
|
||||
The supported dashboards are: `standard`, `rancher`, `openshift`, `gke`, `aks`,
|
||||
`eks` However, not all of them are implemented yet, so please contribute!
|
||||
`eks`. However, not all of them are implemented yet, so please contribute!
|
||||
|
||||
Note that it will default to the regular dashboard provided by the Kubernetes
|
||||
project (`standard`), that can run in any Kubernetes cluster.
|
||||
|
||||
Note that for the `gke` app, you must provide additional information in the
|
||||
`dashboardParameters` option.
|
||||
|
||||
Note that you can add your own formatter by registering it to the
|
||||
`clusterLinksFormatters` dictionary, in the app project.
|
||||
|
||||
@@ -143,6 +151,43 @@ See also
|
||||
https://github.com/backstage/backstage/tree/master/plugins/kubernetes/src/utils/clusterLinks/formatters
|
||||
for real examples.
|
||||
|
||||
##### `clusters.\*.dashboardParameters` (optional)
|
||||
|
||||
Specifies additional information for the selected `dashboardApp` formatter.
|
||||
|
||||
Note that, even though `dashboardParameters` is optional, it might be mandatory
|
||||
for some dashboards, such as GKE.
|
||||
|
||||
###### required parameters for GKE
|
||||
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------ |
|
||||
| projectId | the ID of the GCP project containing your Kubernetes clusters |
|
||||
| region | the region of GCP containing your Kubernetes clusters |
|
||||
| clusterName | the name of your kubernetes cluster, within your `projectId` GCP project |
|
||||
|
||||
Note that the GKE cluster locator can automatically provide the values for the
|
||||
`dashboardApp` and `dashboardParameters` options if you set the
|
||||
`exposeDashboard` property to `true`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
serviceLocatorMethod:
|
||||
type: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- type: 'config'
|
||||
clusters:
|
||||
- url: http://127.0.0.1:9999
|
||||
name: my-cluster
|
||||
dashboardApp: gke
|
||||
dashboardParameters:
|
||||
projectId: my-project
|
||||
region: us-east1
|
||||
clusterName: my-cluster
|
||||
```
|
||||
|
||||
##### `clusters.\*.caData` (optional)
|
||||
|
||||
PEM-encoded certificate authority certificates.
|
||||
@@ -184,6 +229,10 @@ For example:
|
||||
Will configure the Kubernetes plugin to connect to all GKE clusters in the
|
||||
project `gke-clusters` in the region `europe-west1`.
|
||||
|
||||
Note that the GKE cluster locator can automatically provide the values for the
|
||||
`dashboardApp` and `dashboardParameters` options if you enable the
|
||||
`exposeDashboard` option.
|
||||
|
||||
##### `projectId`
|
||||
|
||||
The Google Cloud project to look for Kubernetes clusters in.
|
||||
@@ -203,6 +252,14 @@ presented by the API server. Defaults to `false`.
|
||||
This determines whether the Kubernetes client looks up resource metrics
|
||||
CPU/Memory for pods returned by the API server. Defaults to `false`.
|
||||
|
||||
##### `exposeDashboard`
|
||||
|
||||
This determines wether the `dashboardApp` and `dashboardParameters` should be
|
||||
automatically configured in order to expose the GKE dashboard from the
|
||||
Kubernetes plugin.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### `customResources` (optional)
|
||||
|
||||
Configures which [custom resources][3] to look for when returning an entity's
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -10,8 +10,7 @@ and find catalog entities. This is already set up by default by
|
||||
`@backstage/create-app`.
|
||||
|
||||
If you want to change the default index page - such as to add a custom filter to
|
||||
the catalog - you can replace the routing in `App.tsx` to point to your own
|
||||
`CatalogIndexPage`.
|
||||
the catalog - you can create your own `CatalogIndexPage`.
|
||||
|
||||
> Note: The catalog index page is designed to have a minimal code footprint to
|
||||
> support easy customization, but creating a copy does introduce a possibility
|
||||
@@ -21,23 +20,25 @@ the catalog - you can replace the routing in `App.tsx` to point to your own
|
||||
|
||||
For example, suppose that I want to allow filtering by a custom annotation added
|
||||
to entities, `company.com/security-tier`. To start, I'll copy the code for the
|
||||
default catalog page and create a component in a
|
||||
[new plugin](../../plugins/create-a-plugin.md):
|
||||
default catalog page and create a component.
|
||||
|
||||
```tsx
|
||||
// imports, etc omitted for brevity. for full source see:
|
||||
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
|
||||
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
|
||||
export const CustomCatalogPage = ({
|
||||
columns,
|
||||
actions,
|
||||
initiallySelectedFilter = 'owned',
|
||||
}: CatalogPageProps) => {
|
||||
const createComponentLink = useRouteRef(
|
||||
catalogPlugin.externalRoutes.createComponent,
|
||||
);
|
||||
return (
|
||||
<PageWithHeader title={`${orgName} Catalog`} themeId="home">
|
||||
<EntityListProvider>
|
||||
<Content>
|
||||
<ContentHeader titleComponent={<CatalogKindHeader />}>
|
||||
<CreateButton title="Create Component" to={link} />
|
||||
<CreateButton title="Create Component" to={createComponentLink()} />
|
||||
<SupportButton>All your software catalog entities</SupportButton>
|
||||
</ContentHeader>
|
||||
<FilteredEntityLayout>
|
||||
@@ -167,21 +168,7 @@ export const CustomCatalogPage = ({
|
||||
};
|
||||
```
|
||||
|
||||
This page itself can be exported as a routable extension in the plugin:
|
||||
|
||||
```ts
|
||||
export const CustomCatalogIndexPage = myPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'CustomCatalogIndexPage',
|
||||
component: () =>
|
||||
import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage),
|
||||
mountPoint: catalogRouteRef,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Finally, we can replace the catalog route in the Backstage application with our
|
||||
new `CustomCatalogIndexPage`.
|
||||
Finally, we can apply our new `CustomCatalogPage`.
|
||||
|
||||
```diff
|
||||
# packages/app/src/App.tsx
|
||||
@@ -189,7 +176,9 @@ const routes = (
|
||||
<FlatRoutes>
|
||||
<Navigate key="/" to="catalog" />
|
||||
- <Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
+ <Route path="/catalog" element={<CustomCatalogIndexPage />} />
|
||||
+ <Route path="/catalog" element={<CatalogIndexPage />}>
|
||||
+ <CustomCatalogPage />
|
||||
+ </Route>
|
||||
```
|
||||
|
||||
The same method can be used to customize the _default_ filters with a different
|
||||
|
||||
@@ -10,7 +10,7 @@ TechDocs reads the static generated documentation files from a cloud storage
|
||||
bucket (GCS, AWS S3, etc.). The documentation site is generated on the CI/CD
|
||||
workflow associated with the repository containing the documentation files. This
|
||||
document explains the steps needed to generate docs on CI and publish to a cloud
|
||||
storage using [`techdocs-cli`](https://github.com/backstage/techdocs-cli).
|
||||
storage using [`techdocs-cli`](./cli.md).
|
||||
|
||||
The steps here target all kinds of CI providers (GitHub Actions, CircleCI,
|
||||
Jenkins, etc.). Specific tools for individual providers will also be made
|
||||
@@ -40,9 +40,8 @@ techdocs-cli publish --publisher-type awsS3 --storage-name <bucket/container> --
|
||||
|
||||
That's it!
|
||||
|
||||
Take a look at
|
||||
[`techdocs-cli` README](https://github.com/backstage/techdocs-cli) for the
|
||||
complete command reference, details, and options.
|
||||
Take a look at [`techdocs-cli`](./cli.md) for the complete command reference,
|
||||
details, and options.
|
||||
|
||||
## Steps
|
||||
|
||||
@@ -74,7 +73,7 @@ Install [`npx`](https://www.npmjs.com/package/npx) to use it for running
|
||||
`techdocs-cli`. Or you can install using `npm install -g @techdocs/cli`.
|
||||
|
||||
We are going to use the
|
||||
[`techdocs-cli generate`](https://github.com/backstage/techdocs-cli#generate-techdocs-site-from-a-documentation-project)
|
||||
[`techdocs-cli generate`](./cli.md#generate-techdocs-site-from-a-documentation-project)
|
||||
command in this step.
|
||||
|
||||
```sh
|
||||
@@ -93,8 +92,7 @@ necessary authentication environment variables.
|
||||
- [AWS authentication](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html)
|
||||
|
||||
And then run the
|
||||
[`techdocs-cli publish`](https://github.com/backstage/techdocs-cli#publish-generated-techdocs-sites)
|
||||
command.
|
||||
[`techdocs-cli publish`](./cli.md#publish-generated-techdocs-sites) command.
|
||||
|
||||
```sh
|
||||
npx @techdocs/cli publish --publisher-type <awsS3|googleGcs> --storage-name <bucket/container> --entity <namespace/kind/name> --directory ./site
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -421,3 +421,24 @@ folder (/docs) or replace the content in this file.
|
||||
> on how you have configured your `template.yaml`
|
||||
|
||||
Done! You now have support for TechDocs in your own software template!
|
||||
|
||||
## how to enable iframes in TechDocs
|
||||
|
||||
Techdocs uses the [DOMPurify](https://github.com/cure53/DOMPurify) to sanitizes
|
||||
HTML and prevents XSS attacks
|
||||
|
||||
It's possible to allow some iframes based on a list of allowed hosts. To do
|
||||
this, add the allowed hosts in the `techdocs.sanitizer.allowedIframeHosts`
|
||||
configuration of your `app-config.yaml`
|
||||
|
||||
E.g.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
sanitizer:
|
||||
allowedIframeHosts:
|
||||
- drive.google.com
|
||||
```
|
||||
|
||||
This way, all iframes where the host of src attribute is in the
|
||||
`sanitizer.allowedIframeHosts` list will be displayed
|
||||
|
||||
@@ -53,8 +53,10 @@ To add a custom theme to your Backstage app, you pass it as configuration to
|
||||
For example, adding the theme that we created in the previous section can be
|
||||
done like this:
|
||||
|
||||
```ts
|
||||
```tsx
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
|
||||
const app = createApp({
|
||||
apis: ...,
|
||||
@@ -63,7 +65,11 @@ const app = createApp({
|
||||
id: 'my-theme',
|
||||
title: 'My Custom Theme',
|
||||
variant: 'light',
|
||||
theme: myTheme,
|
||||
Provider: ({ children }) => (
|
||||
<ThemeProvider theme={myTheme}>
|
||||
<CssBaseline>{children}</CssBaseline>
|
||||
</ThemeProvider>
|
||||
),
|
||||
}]
|
||||
})
|
||||
```
|
||||
@@ -76,60 +82,67 @@ want to use the default themes, they are exported as `lightTheme` and
|
||||
## Example of a custom theme
|
||||
|
||||
```ts
|
||||
const themeOptions = createThemeOptions({
|
||||
import {
|
||||
createTheme,
|
||||
genPageTheme,
|
||||
lightTheme,
|
||||
shapes,
|
||||
} from '@backstage/theme';
|
||||
|
||||
const myTheme = createTheme({
|
||||
palette: {
|
||||
...lightTheme.palette,
|
||||
primary: {
|
||||
main: '#123456',
|
||||
main: '#343b58',
|
||||
},
|
||||
secondary: {
|
||||
main: '#123456',
|
||||
main: '#565a6e',
|
||||
},
|
||||
error: {
|
||||
main: '#123456',
|
||||
main: '#8c4351',
|
||||
},
|
||||
warning: {
|
||||
main: '#123456',
|
||||
main: '#8f5e15',
|
||||
},
|
||||
info: {
|
||||
main: '#123456',
|
||||
main: '#34548a',
|
||||
},
|
||||
success: {
|
||||
main: '#123456',
|
||||
main: '#485e30',
|
||||
},
|
||||
background: {
|
||||
default: '#123456',
|
||||
paper: '#123456',
|
||||
default: '#d5d6db',
|
||||
paper: '#d5d6db',
|
||||
},
|
||||
banner: {
|
||||
info: '#123456',
|
||||
error: '#123456',
|
||||
text: '#123456',
|
||||
link: '#123456',
|
||||
info: '#34548a',
|
||||
error: '#8c4351',
|
||||
text: '#343b58',
|
||||
link: '#565a6e',
|
||||
},
|
||||
errorBackground: '#123456',
|
||||
warningBackground: '#123456',
|
||||
infoBackground: '#123456',
|
||||
errorBackground: '#8c4351',
|
||||
warningBackground: '#8f5e15',
|
||||
infoBackground: '#343b58',
|
||||
navigation: {
|
||||
background: '#123456',
|
||||
indicator: '#123456',
|
||||
color: '#123456',
|
||||
selectedColor: '#123456',
|
||||
background: '#343b58',
|
||||
indicator: '#8f5e15',
|
||||
color: '#d5d6db',
|
||||
selectedColor: '#ffffff',
|
||||
},
|
||||
},
|
||||
defaultPageTheme: 'home',
|
||||
fontFamily: 'Comic Sans',
|
||||
fontFamily: 'Comic Sans MS',
|
||||
/* below drives the header colors */
|
||||
pageTheme: {
|
||||
home: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
documentation: genPageTheme(['#123456', '#123456'], shapes.wave2),
|
||||
tool: genPageTheme(['#123456', '#123456'], shapes.round),
|
||||
service: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
website: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
library: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
other: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
app: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
apis: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
home: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
documentation: genPageTheme(['#8c4351', '#343b58'], shapes.wave2),
|
||||
tool: genPageTheme(['#8c4351', '#343b58'], shapes.round),
|
||||
service: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
website: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
library: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
other: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
app: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
apis: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -162,7 +175,7 @@ wouldn't be enough to alter the `box-shadow` property or to add css rules that
|
||||
aren't already defined like a margin. For these cases you should also create an
|
||||
override.
|
||||
|
||||
```ts
|
||||
```tsx
|
||||
import { createApp } from '@backstage/core-app-api';
|
||||
import { BackstageTheme, lightTheme } from '@backstage/theme';
|
||||
/**
|
||||
@@ -187,6 +200,16 @@ export const createCustomThemeOverrides = (
|
||||
};
|
||||
};
|
||||
|
||||
const customTheme: BackstageTheme = {
|
||||
...lightTheme,
|
||||
overrides: {
|
||||
// These are the overrides that Backstage applies to `material-ui` components
|
||||
...lightTheme.overrides,
|
||||
// These are your custom overrides, either to `material-ui` or Backstage components.
|
||||
...createCustomThemeOverrides(lightTheme),
|
||||
},
|
||||
};
|
||||
|
||||
const app = createApp({
|
||||
apis: ...,
|
||||
plugins: ...,
|
||||
@@ -194,15 +217,11 @@ const app = createApp({
|
||||
id: 'my-theme',
|
||||
title: 'My Custom Theme',
|
||||
variant: 'light',
|
||||
theme: {
|
||||
...lightTheme,
|
||||
overrides: {
|
||||
// These are the overrides that Backstage applies to `material-ui` components
|
||||
...lightTheme.overrides,
|
||||
// These are your custom overrides, either to `material-ui` or Backstage components.
|
||||
...createCustomThemeOverrides(lightTheme),
|
||||
},
|
||||
},
|
||||
Provider: ({ children }) => (
|
||||
<ThemeProvider theme={customTheme}>
|
||||
<CssBaseline>{children}</CssBaseline>
|
||||
</ThemeProvider>
|
||||
),
|
||||
}]
|
||||
});
|
||||
```
|
||||
@@ -234,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>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
@@ -215,7 +215,7 @@ days for expiration. If you have a hard time picking a number, we suggest to go
|
||||
for 7 days, it's a lucky number.
|
||||
|
||||
<p align='center'>
|
||||
<img src='../assets/getting-started/gh-oauth.png' alt='Screenshot of the GitHub OAuth creation page' />
|
||||
<img src='../assets/getting-started/gh-pat.png' alt='Screenshot of the GitHub Personal Access Token creation page' />
|
||||
</p>
|
||||
|
||||
Set the scope to your likings. For this tutorial, selecting "repo" should be
|
||||
|
||||
@@ -22,6 +22,13 @@ yarn backstage-cli versions:bump
|
||||
The reason for bumping all `@backstage` packages at once is to maintain the
|
||||
dependencies that they have between each other.
|
||||
|
||||
If you are using other plugins you can pass in the `--pattern` option to update
|
||||
more than just the `@backstage/*` dependencies.
|
||||
|
||||
```bash
|
||||
yarn backstage-cli versions:bump --pattern '@{backstage,roadiehq}/*'
|
||||
```
|
||||
|
||||
## Following create-app template changes
|
||||
|
||||
The `@backstage/create-app` command creates the initial structure of your
|
||||
|
||||
@@ -20,8 +20,7 @@ To use this integration, add configuration to your `app-config.yaml`:
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- host: amazonaws.com
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
- accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
```
|
||||
|
||||
@@ -35,8 +34,21 @@ instruct the AWS S3 reader to assume a role before accessing S3:
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- host: amazonaws.com
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
- accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
roleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/example-role'
|
||||
```
|
||||
|
||||
Configuration allows specifying custom S3 endpoint, along with
|
||||
[path-style access](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html)
|
||||
to support integration with providers like
|
||||
[LocalStack](https://github.com/localstack/localstack):
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- endpoint: 'http://localhost:4566'
|
||||
s3ForcePathStyle: true
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
```
|
||||
|
||||
@@ -434,7 +434,8 @@ Usage: backstage-cli build [options]
|
||||
|
||||
Options:
|
||||
--outputs <formats> List of formats to output [types,cjs,esm]
|
||||
-h, --help display help for command
|
||||
--minify Minify the generated code
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## lint
|
||||
@@ -593,6 +594,7 @@ Usage: backstage-cli versions:bump [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
-p, --pattern Override glob for matching packages to upgrade
|
||||
```
|
||||
|
||||
## versions:check
|
||||
|
||||
@@ -164,12 +164,104 @@ https://circleci.com.
|
||||
|
||||

|
||||
|
||||
## Package Architecture
|
||||
|
||||
Backstage relies heavily on NPM packages, both for distribution of libraries,
|
||||
and structuring of code within projects. While the way you structure your
|
||||
Backstage project is up to you, there is a set of established patterns that we
|
||||
encourage you to follow. These patterns can help set up a sound project
|
||||
structure as well as provide familiarity between different Backstage projects.
|
||||
|
||||
The following diagram shows an overview of the package architecture of
|
||||
Backstage. It takes the point of view of an individual plugin and all of the
|
||||
packages that it may contain, indicated by the thicker border and italic text.
|
||||
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.
|
||||
|
||||

|
||||
|
||||
### Overview
|
||||
|
||||
The arrows in the diagram above indicate a runtime dependency on the code of the
|
||||
target package. This strict dependency graph only applies to runtime
|
||||
`dependencies`, and there may be `devDependencies` that break the rules of this
|
||||
table for the purpose of testing. While there are some arrows that show a
|
||||
dependency on a collection of frontend, backend and isomorphic packages, those
|
||||
still have to abide by important compatibility rules shown in the bottom left.
|
||||
|
||||
The `app` and `backend` packages are the entry points of a Backstage project.
|
||||
The `app` package is the frontend application that brings together a collection
|
||||
of frontend plugins and customizes them to fit an organization, while the
|
||||
`backend` package is the backend service that powers the Backstage application.
|
||||
Worth noting is that there can be more than one instance of each of these
|
||||
packages within a project. Particularly the `backend` packages can benefit from
|
||||
being split up into smaller deployment units that each serve their own purpose
|
||||
with a smaller collection of plugins.
|
||||
|
||||
### Plugin Packages
|
||||
|
||||
A typical plugin consists of up to five packages, two frontend ones, two
|
||||
backend, and one isomorphic packages. All packages within the plugin must share
|
||||
a common prefix, typically of the form `@<scope>/plugin-<plugin-id>`, but
|
||||
alternatives like `backstage-plugin-<plugin-id>` or
|
||||
`@scope/backstage-plugin-<plugin-id>` are also valid. Along with this prefix,
|
||||
each of the packages have their own unique suffix that denotes their role. In
|
||||
addition to these five plugin packages it's also possible for to a plugin to
|
||||
have additional frontend and backend modules that can be installed to enable
|
||||
optional features. For a full list of suffixes and their roles, see the
|
||||
[Plugin Package Structure ADR](../architecture-decisions/adr011-plugin-package-structure.md).
|
||||
|
||||
The `-react`, `-common`, and `-node` plugin packages together form the external
|
||||
library of a plugin. The plugin library enables other plugins to build on top of
|
||||
and extend a plugin, and likewise allows the plugin to depend on and extend
|
||||
other plugins. Because of this, it is preferable that plugin library packages
|
||||
allow duplicate installations of themselves, as you may end up with a mix of
|
||||
versions being installed as dependencies of various plugins. It is also
|
||||
forbidden for plugins to directly import non-library packages from other
|
||||
plugins, all communication between plugins must be handled through libraries and
|
||||
the application itself.
|
||||
|
||||
### Frontend Packages
|
||||
|
||||
The frontend packages are grouped into two main groups. The first one is
|
||||
"Frontend App Core", which is the set of packages that are only used by the
|
||||
`app` package itself. These packages help build up the core structure of the app
|
||||
as well as provide a foundation for the plugin libraries to rely upon.
|
||||
|
||||
The second group is the rest of the shared packages, further divided into
|
||||
"Frontend Plugin Core" and "Frontend Libraries". The core packages that are
|
||||
considered particularly stable and form the core of the frontend framework.
|
||||
Their most important role is to form the boundary around each plugin and provide
|
||||
a set of tools that helps you combine a collection of plugins into a running
|
||||
application. The rest of the frontend packages are more traditional libraries
|
||||
that serve as building blocks to create plugins.
|
||||
|
||||
### Backend Packages
|
||||
|
||||
The backend library packages do not currently share a similar plugin
|
||||
architecture as the frontend packages. They are instead simply a collection of
|
||||
building blocks and patterns that help you build backend services. This is
|
||||
however likely to change in the future.
|
||||
|
||||
### Common Packages
|
||||
|
||||
The common packages are the packages are effectively depended on by all other
|
||||
pages. This is a much smaller set of packages but they are also very pervasive.
|
||||
Because the common packages are isomorphic and must execute both in the frontend
|
||||
and backend, they are never allowed to depend on any of the frontend of backend
|
||||
packages.
|
||||
|
||||
The Backstage CLI is in a category of its own and is depended on by virtually
|
||||
all other packages. It's not a library in itself though, and must always be a
|
||||
development dependency only.
|
||||
|
||||
## Databases
|
||||
|
||||
As we have seen, both the `lighthouse-audit-service` and `catalog-backend`
|
||||
require a database to work with.
|
||||
|
||||
The Backstage backend and its builtin plugins are based on the
|
||||
The Backstage backend and its built-in plugins are based on the
|
||||
[Knex](http://knexjs.org/) library, and set up a separate logical database per
|
||||
plugin. This gives great isolation and lets them perform migrations and evolve
|
||||
separate from each other.
|
||||
@@ -184,7 +276,7 @@ yet.
|
||||
|
||||
## Cache
|
||||
|
||||
The Backstage backend and its builtin plugins are also able to leverage cache
|
||||
The Backstage backend and its built-in plugins are also able to leverage cache
|
||||
stores as a means of improving performance or reliability. Similar to how
|
||||
databases are supported, plugins receive logically separated cache connections,
|
||||
which are powered by [Keyv](https://github.com/lukechilds/keyv) under the hood.
|
||||
|
||||
@@ -55,10 +55,11 @@ learn how to contribute the integration yourself!
|
||||
The following table summarizes events that, depending on the plugins you have
|
||||
installed, may be captured.
|
||||
|
||||
| Action | Provided By | Subject |
|
||||
| ---------- | -------------- | ----------------------------------------- |
|
||||
| `navigate` | Backstage Core | The URL of the page that was navigated to |
|
||||
| `click` | Backstage Core | The text of the link that was clicked on |
|
||||
| Action | Provided By | Subject |
|
||||
| ---------- | -------------- | --------------------------------------------------- |
|
||||
| `navigate` | Backstage Core | The URL of the page that was navigated to |
|
||||
| `click` | Backstage Core | The text of the link that was clicked on |
|
||||
| `search` | Backstage Core | The search term entered in any search bar component |
|
||||
|
||||
If there is an event you'd like to see captured, please [open an
|
||||
issue][add-event] describing the event you want to see and the questions it
|
||||
|
||||
@@ -135,7 +135,7 @@ changes, let's start by wiping this component clean.
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Airbrake
|
||||
author: Simply Business
|
||||
authorUrl: https://github.com/simplybusiness/
|
||||
category: Monitoring
|
||||
description: Access Airbrake error monitoring and other integrations from within Backstage
|
||||
documentation: https://github.com/backstage/backstage/blob/master/plugins/airbrake/README.md
|
||||
iconUrl: https://wp-assets.airbrake.io/wp-content/uploads/2020/10/05222904/Square-white-A-on-Orange.png
|
||||
npmPackageName: '@backstage/plugin-airbrake'
|
||||
@@ -287,7 +287,8 @@
|
||||
"architecture-decisions/adrs-adr009",
|
||||
"architecture-decisions/adrs-adr010",
|
||||
"architecture-decisions/adrs-adr011",
|
||||
"architecture-decisions/adrs-adr012"
|
||||
"architecture-decisions/adrs-adr012",
|
||||
"architecture-decisions/adrs-adr013"
|
||||
],
|
||||
"FAQ": ["FAQ"]
|
||||
}
|
||||
|
||||
@@ -186,6 +186,8 @@ nav:
|
||||
- ADR009 - Entity References: 'architecture-decisions/adr009-entity-references.md'
|
||||
- ADR010 - Luxon Date Library: 'architecture-decisions/adr010-luxon-date-library.md'
|
||||
- ADR011 - Plugin Package Structure: 'architecture-decisions/adr011-plugin-package-structure.md'
|
||||
- ADR012 - Plugin Package Structure: 'architecture-decisions/adr012-use-luxon-locale-and-date-presets.md'
|
||||
- ADR013 - Plugin Package Structure: 'architecture-decisions/adr013-use-node-fetch.md'
|
||||
- Support:
|
||||
- Backstage Project Structure: 'support/project-structure.md'
|
||||
- Glossary: glossary.md
|
||||
|
||||
+3
-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",
|
||||
@@ -55,6 +55,7 @@
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@microsoft/api-documenter": "^7.13.77",
|
||||
"@microsoft/api-extractor": "^7.19.2",
|
||||
"@microsoft/api-extractor-model": "^7.15.1",
|
||||
@@ -68,7 +69,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",
|
||||
|
||||
@@ -1,5 +1,49 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli@0.10.5
|
||||
- @backstage/plugin-search@0.5.4
|
||||
- @backstage/plugin-techdocs@0.12.13
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/plugin-catalog-react@0.6.10
|
||||
- @backstage/plugin-kubernetes@0.5.3
|
||||
- @backstage/core-app-api@0.3.1
|
||||
- @backstage/core-components@0.8.3
|
||||
- @backstage/plugin-apache-airflow@0.1.2
|
||||
- @backstage/plugin-azure-devops@0.1.9
|
||||
- @backstage/plugin-badges@0.2.18
|
||||
- @backstage/plugin-catalog@0.7.7
|
||||
- @backstage/plugin-catalog-graph@0.2.5
|
||||
- @backstage/plugin-catalog-import@0.7.8
|
||||
- @backstage/plugin-circleci@0.2.33
|
||||
- @backstage/plugin-cloudbuild@0.2.31
|
||||
- @backstage/plugin-code-coverage@0.1.21
|
||||
- @backstage/plugin-cost-insights@0.11.16
|
||||
- @backstage/plugin-explore@0.3.24
|
||||
- @backstage/plugin-gcp-projects@0.3.12
|
||||
- @backstage/plugin-github-actions@0.4.30
|
||||
- @backstage/plugin-graphiql@0.2.26
|
||||
- @backstage/plugin-home@0.4.9
|
||||
- @backstage/plugin-jenkins@0.5.16
|
||||
- @backstage/plugin-kafka@0.2.24
|
||||
- @backstage/plugin-lighthouse@0.2.33
|
||||
- @backstage/plugin-newrelic@0.3.12
|
||||
- @backstage/plugin-newrelic-dashboard@0.1.2
|
||||
- @backstage/plugin-org@0.3.33
|
||||
- @backstage/plugin-pagerduty@0.3.21
|
||||
- @backstage/plugin-rollbar@0.3.22
|
||||
- @backstage/plugin-scaffolder@0.11.17
|
||||
- @backstage/plugin-sentry@0.3.32
|
||||
- @backstage/plugin-shortcuts@0.1.18
|
||||
- @backstage/plugin-tech-insights@0.1.4
|
||||
- @backstage/plugin-tech-radar@0.5.1
|
||||
- @backstage/plugin-user-settings@0.3.15
|
||||
- @backstage/plugin-api-docs@0.6.21
|
||||
|
||||
## 0.2.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+43
-42
@@ -1,60 +1,61 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "^0.1.3",
|
||||
"@backstage/catalog-model": "^0.9.8",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/integration-react": "^0.1.16",
|
||||
"@backstage/plugin-api-docs": "^0.6.19",
|
||||
"@backstage/plugin-azure-devops": "^0.1.8",
|
||||
"@backstage/plugin-apache-airflow": "^0.1.1",
|
||||
"@backstage/plugin-badges": "^0.2.17",
|
||||
"@backstage/plugin-catalog": "^0.7.5",
|
||||
"@backstage/plugin-catalog-graph": "^0.2.4",
|
||||
"@backstage/plugin-catalog-import": "^0.7.6",
|
||||
"@backstage/plugin-catalog-react": "^0.6.8",
|
||||
"@backstage/plugin-circleci": "^0.2.32",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.30",
|
||||
"@backstage/plugin-code-coverage": "^0.1.20",
|
||||
"@backstage/plugin-cost-insights": "^0.11.14",
|
||||
"@backstage/plugin-explore": "^0.3.23",
|
||||
"@backstage/plugin-gcp-projects": "^0.3.11",
|
||||
"@backstage/plugin-github-actions": "^0.4.28",
|
||||
"@backstage/plugin-graphiql": "^0.2.25",
|
||||
"@backstage/plugin-home": "^0.4.8",
|
||||
"@backstage/plugin-jenkins": "^0.5.15",
|
||||
"@backstage/plugin-kafka": "^0.2.23",
|
||||
"@backstage/plugin-kubernetes": "^0.5.2",
|
||||
"@backstage/plugin-lighthouse": "^0.2.32",
|
||||
"@backstage/plugin-newrelic": "^0.3.11",
|
||||
"@backstage/plugin-newrelic-dashboard": "^0.1.1",
|
||||
"@backstage/plugin-org": "^0.3.32",
|
||||
"@backstage/plugin-pagerduty": "0.3.20",
|
||||
"@backstage/plugin-rollbar": "^0.3.21",
|
||||
"@backstage/plugin-scaffolder": "^0.11.15",
|
||||
"@backstage/plugin-search": "^0.5.2",
|
||||
"@backstage/plugin-sentry": "^0.3.31",
|
||||
"@backstage/plugin-shortcuts": "^0.1.16",
|
||||
"@backstage/plugin-tech-radar": "^0.5.0",
|
||||
"@backstage/plugin-techdocs": "^0.12.11",
|
||||
"@backstage/plugin-airbrake": "^0.0.0",
|
||||
"@backstage/plugin-api-docs": "^0.6.21",
|
||||
"@backstage/plugin-azure-devops": "^0.1.9",
|
||||
"@backstage/plugin-apache-airflow": "^0.1.2",
|
||||
"@backstage/plugin-badges": "^0.2.18",
|
||||
"@backstage/plugin-catalog": "^0.7.7",
|
||||
"@backstage/plugin-catalog-graph": "^0.2.5",
|
||||
"@backstage/plugin-catalog-import": "^0.7.8",
|
||||
"@backstage/plugin-catalog-react": "^0.6.10",
|
||||
"@backstage/plugin-circleci": "^0.2.33",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.31",
|
||||
"@backstage/plugin-code-coverage": "^0.1.21",
|
||||
"@backstage/plugin-cost-insights": "^0.11.16",
|
||||
"@backstage/plugin-explore": "^0.3.24",
|
||||
"@backstage/plugin-gcp-projects": "^0.3.12",
|
||||
"@backstage/plugin-github-actions": "^0.4.30",
|
||||
"@backstage/plugin-graphiql": "^0.2.26",
|
||||
"@backstage/plugin-home": "^0.4.9",
|
||||
"@backstage/plugin-jenkins": "^0.5.16",
|
||||
"@backstage/plugin-kafka": "^0.2.24",
|
||||
"@backstage/plugin-kubernetes": "^0.5.3",
|
||||
"@backstage/plugin-lighthouse": "^0.2.33",
|
||||
"@backstage/plugin-newrelic": "^0.3.12",
|
||||
"@backstage/plugin-newrelic-dashboard": "^0.1.2",
|
||||
"@backstage/plugin-org": "^0.3.33",
|
||||
"@backstage/plugin-pagerduty": "0.3.21",
|
||||
"@backstage/plugin-rollbar": "^0.3.22",
|
||||
"@backstage/plugin-scaffolder": "^0.11.17",
|
||||
"@backstage/plugin-search": "^0.5.4",
|
||||
"@backstage/plugin-sentry": "^0.3.32",
|
||||
"@backstage/plugin-shortcuts": "^0.1.18",
|
||||
"@backstage/plugin-tech-radar": "^0.5.1",
|
||||
"@backstage/plugin-techdocs": "^0.12.13",
|
||||
"@backstage/plugin-todo": "^0.1.17",
|
||||
"@backstage/plugin-user-settings": "^0.3.14",
|
||||
"@backstage/plugin-user-settings": "^0.3.15",
|
||||
"@backstage/search-common": "^0.2.0",
|
||||
"@backstage/plugin-tech-insights": "^0.1.2",
|
||||
"@backstage/plugin-tech-insights": "^0.1.4",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^1.2.2",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.13",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^1.0.11",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^1.4.2",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^1.3.2",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^1.3.2",
|
||||
"history": "^5.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
|
||||
@@ -42,11 +42,6 @@
|
||||
href="<%= publicPath %>/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<style>
|
||||
#root {
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
<title><%= config.getString('app.title') %></title>
|
||||
|
||||
<% if (config.has('app.googleAnalyticsTrackingId')) { %>
|
||||
@@ -103,7 +98,7 @@
|
||||
<% } %>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0">
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
|
||||
@@ -14,7 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Content, Header, Lifecycle, Page } from '@backstage/core-components';
|
||||
import {
|
||||
CatalogIcon,
|
||||
Content,
|
||||
DocsIcon,
|
||||
Header,
|
||||
Lifecycle,
|
||||
Page,
|
||||
} from '@backstage/core-components';
|
||||
import { CatalogResultListItem } from '@backstage/plugin-catalog';
|
||||
import {
|
||||
DefaultResultListItem,
|
||||
@@ -39,6 +46,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
},
|
||||
filters: {
|
||||
padding: theme.spacing(2),
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -55,12 +63,23 @@ const SearchPage = () => {
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<SearchType.Accordion
|
||||
name="Result Type"
|
||||
defaultValue="software-catalog"
|
||||
types={[
|
||||
{
|
||||
value: 'software-catalog',
|
||||
name: 'Software Catalog',
|
||||
icon: <CatalogIcon />,
|
||||
},
|
||||
{
|
||||
value: 'techdocs',
|
||||
name: 'Documentation',
|
||||
icon: <DocsIcon />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Paper className={classes.filters}>
|
||||
<SearchType
|
||||
values={['techdocs', 'software-catalog']}
|
||||
name="type"
|
||||
defaultValue="software-catalog"
|
||||
/>
|
||||
<SearchFilter.Select
|
||||
className={classes.filter}
|
||||
name="kind"
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 21ae56168e: Updated the Git class with the following:
|
||||
|
||||
- Added `depth` and `noCheckout` options to Git clone, using these you can create a bare clone that includes just the git history
|
||||
- New `log` function which you can use to view the commit history of a git repo
|
||||
|
||||
- eacc582473: Reverted the default CSP configuration to include `'unsafe-eval'` again, which was mistakenly removed in the previous version.
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 94cdf5d1bd: In-memory cache clients instantiated from the same cache manager now share the same memory space.
|
||||
- 916b2f1f3e: Use the default CSP policy provided by `helmet` directly rather than a copy.
|
||||
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
|
||||
- 995e4c7d9d: Added support for non-"amazonaws.com" hosts (for example when testing with LocalStack) in AwsS3UrlReader.
|
||||
- Updated dependencies
|
||||
- @backstage/integration@0.7.0
|
||||
- @backstage/config-loader@0.9.1
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -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>;
|
||||
@@ -234,8 +231,13 @@ export class Git {
|
||||
remote: string;
|
||||
url: string;
|
||||
}): Promise<void>;
|
||||
// (undocumented)
|
||||
clone(options: { url: string; dir: string; ref?: string }): Promise<void>;
|
||||
clone(options: {
|
||||
url: string;
|
||||
dir: string;
|
||||
ref?: string;
|
||||
depth?: number;
|
||||
noCheckout?: boolean;
|
||||
}): Promise<void>;
|
||||
// (undocumented)
|
||||
commit(options: {
|
||||
dir: string;
|
||||
@@ -249,12 +251,10 @@ export class Git {
|
||||
email: string;
|
||||
};
|
||||
}): Promise<string>;
|
||||
// (undocumented)
|
||||
currentBranch(options: {
|
||||
dir: string;
|
||||
fullName?: boolean;
|
||||
}): Promise<string | undefined>;
|
||||
// (undocumented)
|
||||
fetch(options: { dir: string; remote?: string }): Promise<void>;
|
||||
// (undocumented)
|
||||
static fromAuth: (options: {
|
||||
@@ -264,7 +264,7 @@ export class Git {
|
||||
}) => Git;
|
||||
// (undocumented)
|
||||
init(options: { dir: string; defaultBranch?: string }): Promise<void>;
|
||||
// (undocumented)
|
||||
log(options: { dir: string; ref?: string }): Promise<ReadCommitResult[]>;
|
||||
merge(options: {
|
||||
dir: string;
|
||||
theirs: string;
|
||||
@@ -280,9 +280,7 @@ export class Git {
|
||||
}): Promise<MergeResult>;
|
||||
// (undocumented)
|
||||
push(options: { dir: string; remote: string }): Promise<PushResult>;
|
||||
// (undocumented)
|
||||
readCommit(options: { dir: string; sha: string }): Promise<ReadCommitResult>;
|
||||
// (undocumented)
|
||||
resolveRef(options: { dir: string; ref: string }): Promise<string>;
|
||||
}
|
||||
|
||||
@@ -309,7 +307,7 @@ export class GithubUrlReader implements UrlReader {
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class GitlabUrlReader implements UrlReader {
|
||||
constructor(
|
||||
integration: GitLabIntegration,
|
||||
@@ -397,7 +395,7 @@ export type ReadTreeResponseDirOptions = {
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface ReadTreeResponseFactory {
|
||||
// (undocumented)
|
||||
fromReadableArray(
|
||||
@@ -447,7 +445,7 @@ export type ReadUrlResponse = {
|
||||
// @public
|
||||
export function requestLoggingHandler(logger?: Logger_2): RequestHandler;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type RequestLoggingHandlerFactory = (
|
||||
logger?: Logger_2,
|
||||
) => RequestHandler;
|
||||
@@ -458,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[];
|
||||
@@ -507,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;
|
||||
@@ -533,7 +531,7 @@ export type ServiceBuilder = {
|
||||
start(): Promise<Server>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function setRootLogger(newLogger: winston.Logger): void;
|
||||
|
||||
// @public @deprecated
|
||||
@@ -553,7 +551,7 @@ export class SingleHostDiscovery implements PluginEndpointDiscovery {
|
||||
getExternalBaseUrl(pluginId: string): Promise<string>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type StatusCheck = () => Promise<any>;
|
||||
|
||||
// @public
|
||||
@@ -561,7 +559,7 @@ export function statusCheckHandler(
|
||||
options?: StatusCheckHandlerOptions,
|
||||
): Promise<RequestHandler>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface StatusCheckHandlerOptions {
|
||||
statusCheck?: StatusCheck;
|
||||
}
|
||||
@@ -596,7 +594,7 @@ export class UrlReaders {
|
||||
static default(options: UrlReadersOptions): UrlReader;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type UrlReadersOptions = {
|
||||
config: Config;
|
||||
logger: Logger_2;
|
||||
@@ -611,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
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -31,12 +31,12 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.6",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/config-loader": "^0.9.0",
|
||||
"@backstage/config-loader": "^0.9.1",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@google-cloud/storage": "^5.8.0",
|
||||
"@lerna/project": "^4.0.0",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/dockerode": "^3.3.0",
|
||||
@@ -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",
|
||||
@@ -81,8 +81,8 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/concat-stream": "^1.6.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
|
||||
|
||||
@@ -147,6 +147,22 @@ describe('CacheManager', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('shares memory across multiple instances of the memory client', () => {
|
||||
const manager = CacheManager.fromConfig(defaultConfig());
|
||||
const plugin = 'test-plugin';
|
||||
|
||||
// Instantiate two in-memory clients.
|
||||
manager.forPlugin(plugin).getClient({ defaultTtl: 10 });
|
||||
manager.forPlugin(plugin).getClient({ defaultTtl: 10 });
|
||||
|
||||
const cache = Keyv as unknown as jest.Mock;
|
||||
const mockCall2 = cache.mock.calls.splice(-1)[0][0];
|
||||
const mockCall1 = cache.mock.calls.splice(-1)[0][0];
|
||||
|
||||
// Note: .toBe() checks referential identity of object instances.
|
||||
expect(mockCall1.store).toBe(mockCall2.store);
|
||||
});
|
||||
|
||||
it('returns a memcache client when configured', () => {
|
||||
const expectedHost = '127.0.0.1:11211';
|
||||
const manager = CacheManager.fromConfig(
|
||||
|
||||
+12
-3
@@ -42,14 +42,21 @@ export class CacheManager {
|
||||
none: this.getNoneClient,
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared memory store for the in-memory cache client. Sharing the same Map
|
||||
* instance ensures get/set/delete operations hit the same store, regardless
|
||||
* of where/when a client is instantiated.
|
||||
*/
|
||||
private readonly memoryStore = new Map();
|
||||
|
||||
private readonly logger: Logger;
|
||||
private readonly store: keyof CacheManager['storeFactories'];
|
||||
private readonly connection: string;
|
||||
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.
|
||||
*/
|
||||
@@ -86,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 {
|
||||
@@ -133,6 +141,7 @@ export class CacheManager {
|
||||
return new Keyv({
|
||||
namespace: pluginId,
|
||||
ttl: defaultTtl,
|
||||
store: this.memoryStore,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+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;
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
} from '@backstage/config-loader';
|
||||
import { AppConfig, Config, ConfigReader } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { getPackages } from '@manypkg/get-packages';
|
||||
|
||||
import { isValidUrl } from './urls';
|
||||
|
||||
@@ -194,11 +195,9 @@ export async function loadBackendConfig(options: {
|
||||
// TODO(hhogg): This is fetching _all_ of the packages of the monorepo
|
||||
// in order to find the secrets for redactions, however we only care about
|
||||
// the backend ones, we need to find a way to exclude the frontend packages.
|
||||
const { Project } = require('@lerna/project');
|
||||
const project = new Project(paths.targetDir);
|
||||
const packages = await project.getPackages();
|
||||
const { packages } = await getPackages(paths.targetDir);
|
||||
const schema = await loadConfigSchema({
|
||||
dependencies: packages.map((p: any) => p.name),
|
||||
dependencies: packages.map(p => p.packageJson.name),
|
||||
});
|
||||
|
||||
const config = new ObservableConfigProxy(options.logger);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -20,8 +20,8 @@ import { merge } from 'lodash';
|
||||
* Merges database objects together
|
||||
*
|
||||
* @public
|
||||
* @param config The base config. The input is not modified
|
||||
* @param overrides Any additional overrides
|
||||
* @param config - The base config. The input is not modified
|
||||
* @param overrides - Any additional overrides
|
||||
*/
|
||||
export function mergeDatabaseConfig(config: any, ...overrides: any[]) {
|
||||
return merge({}, config, ...overrides);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Knex } from 'knex';
|
||||
* Default override for knex database drivers which accept ConnectionConfig
|
||||
* with `connection.database` as the database name field.
|
||||
*
|
||||
* @param name database name to get config override for
|
||||
* @param name - database name to get config override for
|
||||
*/
|
||||
export default function defaultNameOverride(
|
||||
name: string,
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Knex } from 'knex';
|
||||
/**
|
||||
* Provides a partial knex config with schema name override.
|
||||
*
|
||||
* @param name schema name to get config override for
|
||||
* @param name - schema name to get config override for
|
||||
*/
|
||||
export default function defaultSchemaOverride(
|
||||
name: string,
|
||||
|
||||
@@ -26,8 +26,8 @@ import defaultNameOverride from './defaultNameOverride';
|
||||
/**
|
||||
* Creates a knex mysql database connection
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function createMysqlDatabaseClient(
|
||||
dbConfig: Config,
|
||||
@@ -41,8 +41,8 @@ export function createMysqlDatabaseClient(
|
||||
/**
|
||||
* Builds a knex mysql database connection
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function buildMysqlDatabaseConfig(
|
||||
dbConfig: Config,
|
||||
@@ -61,8 +61,8 @@ export function buildMysqlDatabaseConfig(
|
||||
/**
|
||||
* Gets the mysql connection config
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param parseConnectionString Flag to explicitly control connection string parsing
|
||||
* @param dbConfig - The database config
|
||||
* @param parseConnectionString - Flag to explicitly control connection string parsing
|
||||
*/
|
||||
export function getMysqlConnectionConfig(
|
||||
dbConfig: Config,
|
||||
@@ -86,7 +86,7 @@ export function getMysqlConnectionConfig(
|
||||
* Parses a mysql connection string.
|
||||
*
|
||||
* e.g. mysql://examplename:somepassword@examplehost:3306/dbname
|
||||
* @param connectionString The mysql connection string
|
||||
* @param connectionString - The mysql connection string
|
||||
*/
|
||||
export function parseMysqlConnectionString(
|
||||
connectionString: string,
|
||||
@@ -140,8 +140,8 @@ export function parseMysqlConnectionString(
|
||||
/**
|
||||
* Creates the missing mysql database if it does not exist
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param databases The names of the databases to create
|
||||
* @param dbConfig - The database config
|
||||
* @param databases - The names of the databases to create
|
||||
*/
|
||||
export async function ensureMysqlDatabaseExists(
|
||||
dbConfig: Config,
|
||||
|
||||
@@ -26,8 +26,8 @@ import defaultSchemaOverride from './defaultSchemaOverride';
|
||||
/**
|
||||
* Creates a knex postgres database connection
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function createPgDatabaseClient(
|
||||
dbConfig: Config,
|
||||
@@ -41,8 +41,8 @@ export function createPgDatabaseClient(
|
||||
/**
|
||||
* Builds a knex postgres database connection
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function buildPgDatabaseConfig(
|
||||
dbConfig: Config,
|
||||
@@ -61,8 +61,8 @@ export function buildPgDatabaseConfig(
|
||||
/**
|
||||
* Gets the postgres connection config
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param parseConnectionString Flag to explicitly control connection string parsing
|
||||
* @param dbConfig - The database config
|
||||
* @param parseConnectionString - Flag to explicitly control connection string parsing
|
||||
*/
|
||||
export function getPgConnectionConfig(
|
||||
dbConfig: Config,
|
||||
@@ -85,7 +85,7 @@ export function getPgConnectionConfig(
|
||||
/**
|
||||
* Parses a connection string using pg-connection-string
|
||||
*
|
||||
* @param connectionString The postgres connection string
|
||||
* @param connectionString - The postgres connection string
|
||||
*/
|
||||
export function parsePgConnectionString(connectionString: string) {
|
||||
const parse = requirePgConnectionString();
|
||||
@@ -103,8 +103,8 @@ function requirePgConnectionString() {
|
||||
/**
|
||||
* Creates the missing Postgres database if it does not exist
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param databases The name of the databases to create
|
||||
* @param dbConfig - The database config
|
||||
* @param databases - The name of the databases to create
|
||||
*/
|
||||
export async function ensurePgDatabaseExists(
|
||||
dbConfig: Config,
|
||||
@@ -139,8 +139,8 @@ export async function ensurePgDatabaseExists(
|
||||
/**
|
||||
* Creates the missing Postgres schema if it does not exist
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param schemas The name of the schemas to create
|
||||
* @param dbConfig - The database config
|
||||
* @param schemas - The name of the schemas to create
|
||||
*/
|
||||
export async function ensurePgSchemaExists(
|
||||
dbConfig: Config,
|
||||
|
||||
@@ -25,8 +25,8 @@ import { DatabaseConnector } from '../types';
|
||||
/**
|
||||
* Creates a knex SQLite3 database connection
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function createSqliteDatabaseClient(
|
||||
dbConfig: Config,
|
||||
@@ -58,8 +58,8 @@ export function createSqliteDatabaseClient(
|
||||
/**
|
||||
* Builds a knex SQLite3 connection config
|
||||
*
|
||||
* @param dbConfig The database config
|
||||
* @param overrides Additional options to merge with the config
|
||||
* @param dbConfig - The database config
|
||||
* @param overrides - Additional options to merge with the config
|
||||
*/
|
||||
export function buildSqliteDatabaseConfig(
|
||||
dbConfig: Config,
|
||||
|
||||
@@ -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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user