Merge remote-tracking branch 'origin/master' into mob/scaffolder-frontend

This commit is contained in:
Johan Haals
2021-02-11 14:42:42 +01:00
349 changed files with 11185 additions and 3477 deletions
-29
View File
@@ -1,29 +0,0 @@
---
'@backstage/create-app': patch
---
Pass on plugin database management instance that is now required by the scaffolder plugin.
To apply this change to an existing application, add the following to `src/plugins/scaffolder.ts`:
```diff
export default async function createPlugin({
logger,
config,
+ database,
}: PluginEnvironment) {
// ...omitted...
return await createRouter({
preparers,
templaters,
publishers,
logger,
config,
dockerClient,
entityClient,
+ database,
});
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-circleci': patch
---
Migrated to new composability API, exporting the plugin instance as `circleCIPlugin`, the entity page content as `EntityCircleCIContent`, and entity conditional as `isCircleCIAvailable`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search': minor
---
Migrated to new composability API, exporting the plugin instance as `searchPlugin`, and page as `SearchPage`. Due to the old router component also being called `SearchPage`, this is a breaking change. The old page component is now exported as `Router`, which can be used to maintain the old behavior.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Don't respond to a request twice if an entity has not been found.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-cloudbuild': patch
---
Migrate to new composability API, exporting the plugin instance as `cloudbuildPlugin`, the entity content as `EntityCloudbuildContent`, the entity conditional as `isCloudbuildAvailable`, and entity cards as `EntityLatestCloudbuildRunCard` and `EntityLatestCloudbuildsForBranchCard`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-register-component': patch
---
Migrated to new composability API, exporting the plugin instance as `registerComponentPlugin`, and page as `RegisterComponentPage`.
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Introduced `v2` Scaffolder REST API, which uses an implementation that is database backed, making the scaffolder instances stateless. The `createRouter` function now requires a `PluginDatabaseManager` instance to be passed in, commonly available as `database` in the plugin environment in the backend.
This API should be considered unstable until used by the scaffolder frontend.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Migrated to new composability API, exporting the plugin instance as `techdocsPlugin`, the top-level page as `TechdocsPage`, and the entity content as `EntityTechdocsContent`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Limit the props that are forwarded to the `Link` component in the `EntityRefLink`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-common': patch
---
Slight refactoring in support of a future search implementation in `UrlReader`. Mostly moving code around.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-pagerduty': patch
---
Migrated to new composability API, exporting the plugin instance as `pagerDutyPlugin`, entity card as `EntityPagerDutyCard`, and entity conditional as `isPagerDutyAvailable`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/test-utils': patch
---
Added `mountedRoutes` option to `wrapInTestApp`, allowing routes to be associated to concrete paths to make `useRouteRef` usable in tested components.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-jenkins': patch
---
Migrate to new composability API, exporting the plugin instance as `jenkinsPlugin`, the entity content as `EntityJenkinsContent`, the entity conditional as `isJenkinsAvailable`, and the entity card as `EntityLatestJenkinsRunCard`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-github-actions': patch
---
Migrate to new composability API, exporting the plugin instance as `githubActionsPlugin`, the entity content as `EntityGithubActionsContent`, entity conditional as `isGithubActionsAvailable`, and entity cards as `EntityLatestGithubActionRunCard`, `EntityLatestGithubActionsForBranchCard`, and `EntityRecentGithubActionsRunsCard`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-newrelic': patch
---
Migrate to new composability API, exporting the plugin instance as `newRelicPlugin`, and the root page as `NewRelicPage`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes': patch
---
Migrate to new composability API, exporting the plugin instance as `kubernetesPlugin` and entity content as `EntityKubernetesContent`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kafka': patch
---
Migrate to new composability API, exporting the plugin instance as `kafkaPlugin`, entity content as `EntityKafkaContent`, and entity conditional as `isKafkaAvailable`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Migrated the package from using moment to Luxon. #4278
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Enhance API calls to support trapping 500 errors from techdocs-backend
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core': patch
---
Make sure that SidebarItems are also active when on sub route.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core': patch
---
Fixed type inference of `createRouteRef`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-gitops-profiles': patch
---
Migrated to new composability API, exporting the plugin instance as `gitopsProfilesPlugin` and pages as `GitopsProfilesClusterListPage`, `GitopsProfilesClusterPage`, and `GitopsProfilesCreatePage`.
+1
View File
@@ -7,6 +7,7 @@
* @backstage/maintainers
/docs/features/techdocs @backstage/techdocs-core
/docs/features/search @backstage/techdocs-core
/docs/assets/search @backstage/techdocs-core
/plugins/cost-insights @backstage/silver-lining
/plugins/cloudbuild @trivago/ebarrios
/plugins/search @backstage/techdocs-core
+1
View File
@@ -249,6 +249,7 @@ transpilation
Tuite
ui
unmanaged
unregister
untracked
upvote
url
+1 -1
View File
@@ -77,7 +77,7 @@ jobs:
run: yarn prettier:check
- name: validate config
run: yarn backstage-cli config:check
run: yarn backstage-cli config:check --lax
- name: lint
run: yarn lerna -- run lint --since origin/master
+1 -1
View File
@@ -65,7 +65,7 @@ jobs:
COMMIT_SHA_BEFORE: '${{ github.event.before }}'
- name: validate config
run: yarn backstage-cli config:check
run: yarn backstage-cli config:check --lax
- name: lint
run: yarn lerna -- run lint
+24 -4
View File
@@ -48,11 +48,14 @@ jobs:
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '14'
- name: yarn install
run: yarn --cwd cypress install
# This is required because the environment_url param that Tugboat uses
# to tell us where the preview is located isn't supported unless you
# specify the custom Accept header when getting the deployment_status,
@@ -77,9 +80,25 @@ jobs:
});
console.log(result);
return result.data.environment_url;
- name: echo tugboat preview url
run: |
curl ${{steps.get-status-env.outputs.result}}
- name: cypress run
uses: cypress-io/github-action@v2
env:
CYPRESS_baseUrl: ${{steps.get-status-env.outputs.result}}
with:
config-file: ./cypress.json
working-directory: ./cypress
browser: chrome
install: false
headless: true
- name: update artifact
if: ${{ always() }}
uses: actions/upload-artifact@v1
with:
name: cypress-videos
path: ./cypress/cypress/videos
- name: set status
if: ${{ failure() }}
uses: actions/github-script@v3
@@ -94,6 +113,7 @@ jobs:
context: 'Backstage Tugboat E2E Tests',
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
- name: set status
if: ${{ success() }}
uses: actions/github-script@v3
+1
View File
@@ -53,6 +53,7 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
- [Adopters](ADOPTERS.md) - Companies already using Backstage
- [Blog](https://backstage.io/blog/) - Announcements and updates
- [Newsletter](https://mailchi.mp/spotify/backstage-community) - Subscribe to our email newsletter
- [Backstage Community Sessions](https://github.com/backstage/community) - Join monthly meetup and explore Backstage community
- Give us a star ⭐️ - If you are using Backstage or think it is an interesting project, we would love a star ❤️
## License
+7
View File
@@ -73,6 +73,9 @@ organization:
name: My Company
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
# Note: After experimenting with basic setup, use CI/CD to generate docs
# and an external cloud storage when deploying TechDocs for production use-case.
# https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach
techdocs:
builder: 'local' # Alternatives - 'external'
generators:
@@ -305,6 +308,10 @@ auth:
$env: AUTH_OAUTH2_AUTH_URL
tokenUrl:
$env: AUTH_OAUTH2_TOKEN_URL
###
# provide a list of scopes as needed for your OAuth2 Server:
#
# scope: saml-login-selector openid profile email
oidc:
development:
metadataUrl:
+17
View File
@@ -0,0 +1,17 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
rules: {
'no-console': 0,
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: true,
optionalDependencies: false,
peerDependencies: false,
bundledDependencies: false,
},
],
'jest/expect-expect': 'off',
'no-restricted-syntax': 'off',
},
};
+27
View File
@@ -0,0 +1,27 @@
# Cypress Tests for Backstage
Hey 👋 Welcome to the Cypress tests for Backstage. They're designed to be run against the `packages/app` folder in the main repo, and be some form of smoke tests to make sure that we don't break any core functionality.
They run part of the PR build, and are triggered from the `.github/workflows/tugboat.yml` file.
The main app gets built up part of a [Tugboat Build](https://tugboat.qa), which when complete, sends a `deployment event` to the PR triggering the aforementioned workflow.
### Running Locally
In order to make typescript happy, this `cypress` package is separate from all the Jest dependencies in the monorepo workspaces setup.
You can run the e2e tests locally pointing at your local running version like so:
```sh
cd cypress
yarn install
yarn cypress run
```
You can open up the `cypress` console by using `yarn cypress open`.
You can also run towards any Backstage installation by using the Cypress Environment Variable overrides.
```sh
CYPRESS_baseUrl="http://demo.backstage.io" yarn cypress run
```
+8
View File
@@ -0,0 +1,8 @@
{
"baseUrl": "http://localhost:7000",
"integrationFolder": "./src/integration",
"supportFile": "./src/support",
"fixturesFolder": "./src/fixures",
"pluginsFile": "./src/plugins",
"defaultCommandTimeout": 10000
}
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@backstage/cypress-tests",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"dependencies": {
"cypress": "^6.4.0",
"typescript": "^4.1.3"
}
}
View File
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types="cypress" />
import 'os';
describe('Catalog', () => {
describe('default entities', () => {
it('displays the correct amount of entities from default config', () => {
cy.loginAsGuest();
cy.visit('/catalog');
cy.contains('Owned (7)').should('be.visible');
});
});
});
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default () => {};
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types="cypress" />
Cypress.Commands.add('loginAsGuest', () => {
cy.visit('/', {
onLoad: (win: Window) =>
win.localStorage.setItem('@backstage/core:SignInPage:provider', 'guest'),
});
});
export {};
@@ -13,19 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import parseGitUrl from 'git-url-parse';
export type UrlType = 'file' | 'tree';
export function urlType(url: string): UrlType {
const { filepathtype, filepath } = parseGitUrl(url);
if (filepathtype === 'tree' || filepathtype === 'file') {
return filepathtype;
} else if (filepath?.match(/\.ya?ml$/)) {
return 'file';
declare module 'zombie';
declare module 'pgtools';
declare namespace Cypress {
interface Chainable {
/**
* Login as guest
* @example cy.loginAsGuests
*/
loginAsGuest(): Chainable<Element>;
}
return 'tree';
}
+37
View File
@@ -0,0 +1,37 @@
{
"compilerOptions": {
"allowJs": true,
"declaration": true,
"declarationMap": false,
"esModuleInterop": true,
"experimentalDecorators": false,
"forceConsistentCasingInFileNames": true,
"importHelpers": false,
"incremental": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2020", "ESNext.Promise"],
"module": "ESNext",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"pretty": true,
"removeComments": false,
"resolveJsonModule": true,
"sourceMap": false,
"skipLibCheck": false,
"strict": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"stripInternal": true,
"target": "ES2019",
"types": ["node", "cypress"]
}
}
+1409
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -119,7 +119,7 @@ Plugins supply their APIs through the `apis` option of `createPlugin`, for
example:
```ts
export const plugin = createPlugin({
export const techdocsPlugin = createPlugin({
id: 'techdocs',
apis: [
createApiFactory({
+45 -26
View File
@@ -1,13 +1,13 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="789px" height="766px" viewBox="-0.5 -0.5 789 766" content="&lt;mxfile host=&quot;bd2205bb-07f8-4b61-b1c1-5174fe4ebe37&quot; modified=&quot;2021-01-14T13:46:42.842Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.52.0 Chrome/83.0.4103.122 Electron/9.3.5 Safari/537.36&quot; etag=&quot;jW9IV2PM6529z9FP4d6-&quot; version=&quot;13.10.0&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;AOZgdlUmH_6GT6Gt5u4e&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="789px" height="766px" viewBox="-0.5 -0.5 789 766" content="&lt;mxfile host=&quot;be2f1433-9da5-431b-92db-92882262d7d1&quot; modified=&quot;2021-02-10T13:37:29.724Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.53.0 Chrome/87.0.4280.141 Electron/11.2.1 Safari/537.36&quot; etag=&quot;EtMH9Eo_7GPdazvr9TBW&quot; version=&quot;14.2.4&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;AOZgdlUmH_6GT6Gt5u4e&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<defs/>
<g>
<rect x="560" y="484" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="420" y="484" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<path d="M 664.5 595 L 664.5 705 L 595.54 705" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 590.29 705 L 597.29 701.5 L 595.54 705 L 597.29 708.5 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<rect x="420" y="110" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="420" y="110" width="135" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="420" y="299" width="280" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="560" y="110" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="565" y="110" width="135" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<rect x="90" y="469.25" width="110" height="90" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
@@ -66,24 +66,26 @@
</text>
</switch>
</g>
<rect x="415" y="90" width="210" height="20" fill="none" stroke="none" pointer-events="all"/>
<rect x="419.59" y="80" width="140" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 100px; margin-left: 520px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 95px; margin-left: 422px;">
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
@backstage/plugin-search-backend
@backstage/
<br/>
plugin-search-backend
</div>
</div>
</div>
</foreignObject>
<text x="520" y="104" fill="#5C5C5C" font-family="Helvetica" font-size="12px" text-anchor="middle">
@backstage/plugin-search-backend
<text x="422" y="99" fill="#5C5C5C" font-family="Helvetica" font-size="12px">
@backstage/...
</text>
</switch>
</g>
<rect x="90" y="433.75" width="160" height="30" fill="none" stroke="none" pointer-events="all"/>
<rect x="90" y="433.75" width="150" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
@@ -138,9 +140,9 @@
</text>
</switch>
</g>
<path d="M 630 364.25 L 758 364.3 L 758 177.3 L 661.87 177.25" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 656.62 177.25 L 663.62 173.75 L 661.87 177.25 L 663.62 180.75 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<rect x="415" y="279" width="280" height="20" fill="none" stroke="none" pointer-events="all"/>
<path d="M 636.37 364.25 L 758 364.3 L 758 177.3 L 655.5 177.25" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 631.12 364.25 L 638.12 360.75 L 636.37 364.25 L 638.12 367.75 Z" fill="#006658" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<rect x="420" y="279" width="270" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
@@ -266,7 +268,7 @@
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 220px; margin-left: 351px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 220px; margin-left: 350px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
Pass Search
@@ -280,7 +282,7 @@
</div>
</div>
</foreignObject>
<text x="351" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
<text x="350" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
Pass Search...
</text>
</switch>
@@ -352,8 +354,8 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 49px; height: 1px; padding-top: 165px; margin-left: 606px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<font style="font-size: 9px">
Gather Documents
<font style="font-size: 7px">
Gather Documents From Plugins
</font>
</div>
</div>
@@ -366,7 +368,7 @@
</g>
<path d="M 444.17 349.5 C 444.17 341.22 453.31 334.5 464.59 334.5 C 470.01 334.5 475.2 336.08 479.03 338.89 C 482.86 341.71 485.01 345.52 485.01 349.5 L 485.01 379 C 485.01 387.28 475.87 394 464.59 394 C 453.31 394 444.17 387.28 444.17 379 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 485.01 349.5 C 485.01 357.78 475.87 364.5 464.59 364.5 C 453.31 364.5 444.17 357.78 444.17 349.5" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 550 364.25 L 517.5 364.3 L 485.01 364.3" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 550 364.25 L 517.5 364.3 L 485.01 364.25" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<rect x="550" y="324.25" width="80" height="80" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
@@ -375,16 +377,14 @@
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<font style="font-size: 11px">
Collate Documents
<br/>
Or Metadata
Register Document / Metadata Collation Handler(s)
</font>
</div>
</div>
</div>
</foreignObject>
<text x="590" y="368" fill="#FFFFFF" font-family="Helvetica" font-size="12px" text-anchor="middle">
Collate Docum...
Register Docu...
</text>
</switch>
</g>
@@ -427,11 +427,11 @@
</text>
</switch>
</g>
<rect x="560" y="110" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
<rect x="565" y="110" width="80" height="20" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 120px; margin-left: 600px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 120px; margin-left: 605px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #FFFFFF; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
<font style="font-size: 9px">
@@ -441,7 +441,7 @@
</div>
</div>
</foreignObject>
<text x="600" y="123" fill="#FFFFFF" font-family="Helvetica" font-size="11px" text-anchor="middle">
<text x="605" y="123" fill="#FFFFFF" font-family="Helvetica" font-size="11px" text-anchor="middle">
Index Processi...
</text>
</switch>
@@ -529,10 +529,29 @@
</text>
</switch>
</g>
<rect x="565" y="80" width="130" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 95px; margin-left: 567px;">
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
@backstage/
<br/>
plugin-search-indexer
</div>
</div>
</div>
</foreignObject>
<text x="567" y="99" fill="#5C5C5C" font-family="Helvetica" font-size="12px">
@backstage/...
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank">
<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>

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 46 KiB

+22 -8
View File
@@ -76,14 +76,16 @@ by also providing the `cert` configuration.
### Configuration
Each authentication provider (except SAML) needs five parameters: an OAuth
client ID, a client secret, an authorization endpoint, a token endpoint, and an
app origin. The app origin is the URL at which the frontend of the application
is hosted, and it is read from the `app.baseUrl` config. This is required
because the application opens a popup window to perform the authentication, and
once the flow is completed, the popup window sends a `postMessage` to the
frontend application to indicate the result of the operation. Also this URL is
used to verify that authentication requests are coming from only this endpoint.
Each authentication provider (except SAML) needs six parameters: an OAuth client
ID, a client secret, an authorization endpoint, a token endpoint, an optional
list of scopes (as a string separated by spaces) that may be required by the
OAuth2 Server to enable end-user sign-on, and an app origin. The app origin is
the URL at which the frontend of the application is hosted, and it is read from
the `app.baseUrl` config. This is required because the application opens a popup
window to perform the authentication, and once the flow is completed, the popup
window sends a `postMessage` to the frontend application to indicate the result
of the operation. Also this URL is used to verify that authentication requests
are coming from only this endpoint.
These values are configured via the `app-config.yaml` present in the root of
your app folder.
@@ -109,6 +111,18 @@ auth:
development:
clientId:
$env:
oauth2:
development:
clientId:
$env: AUTH_OAUTH2_CLIENT_ID
clientSecret:
$env: AUTH_OAUTH2_CLIENT_SECRET
authorizationUrl:
$env: AUTH_OAUTH2_AUTH_URL
tokenUrl:
$env: AUTH_OAUTH2_TOKEN_URL
scope:
$env: AUTH_OAUTH2_SCOPE
saml:
entryPoint:
$env: AUTH_SAML_ENTRY_POINT
+12 -6
View File
@@ -24,12 +24,18 @@ Backstage ecosystem.
## Project roadmap
| Version | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Backstage Search V.0 ✅ | Search Frontend letting you search through the entities of the software catalog. [See V.0 Use Cases.](#backstage-search-v0) |
| Backstage Search V.1 ⌛ | Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog. [See V.1 Use Cases.](#backstage-search-v1) |
| Backstage Search V.2 ⌛ | Search Backend responsible for the indexing process of entities, and their metadata, registered to the Software Catalog. [See V.2 Use Cases.](#backstage-search-v2) |
| Backstage Search V.3 ⌛ | Standardized Search API lets you index other plugins data to the search engine of choice. [See V.3 Use Cases.](#backstage-search-v3) |
| Version | Description |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Backstage Search v0 ✅ | Search Frontend letting you search through the entities of the software catalog. [See v0 Use Cases.](#backstage-search-v0) |
| [Backstage Search V0.5 ⌛][v0.5] | Foundations for the architecture. |
| [Backstage Search v1 ⌛][v1] | Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog. [See v1 Use Cases.](#backstage-search-v1) |
| [Backstage Search v2 ⌛][v2] | Search Backend responsible for the indexing process of entities, and their metadata, registered to the Software Catalog. [See v2 Use Cases.](#backstage-search-v2) |
| [Backstage Search v3 ⌛][v3] | Standardized Search API lets you index other plugins data to the search engine of choice. [See v3 Use Cases.](#backstage-search-v3) |
[v0.5]: https://github.com/backstage/backstage/milestone/25
[v1]: https://github.com/backstage/backstage/milestone/26
[v2]: https://github.com/backstage/backstage/milestone/27
[v3]: https://github.com/backstage/backstage/milestone/28
## Use Cases
+19 -10
View File
@@ -6,9 +6,9 @@ description: Documentation on Search Architecture
# Search Architecture
> _This is a proposed architecture which has not been implemented yet. We are
> still looking for feedback to improve the architecture to fit your use-case,
> see [this open issue](https://github.com/backstage/backstage/issues/4078)._
> _This is a proposed architecture which has not been implemented yet. Find our
> milestones to follow our progress on the
> [Search Roadmap](./README.md#project-roadmap)._
Below you can explore the Search Architecture. Our aim with this architecture is
to support a wide variety of search engines, while providing a simple developer
@@ -20,7 +20,10 @@ Backstage end-users.
At a base-level, we want to support the following:
- We aim to enable the capability to search across the entire Backstage
ecosystem by decoupling search from content management.
ecosystem including, but not limited to, entities in the software catalog.
Searchable content won't be required to relate directly to the software
catalog, but by convention, we may encourage loose relationships using
well-known field names or attributes.
- We aim to enable the capability to deploy Backstage using any search engine,
by providing an integration and translation layer between the core search
plugin and search engine specific logic that can be extended for different
@@ -29,11 +32,17 @@ At a base-level, we want to support the following:
More advanced use-cases we hope to support with this architecture include:
- It should be easy for any plugin to expose new content to search. (e.g. entity
metadata, documentation from TechDocs)
- It should be easy for any plugin to append relevant metadata to existing
- It should be possible for any plugin to expose new content to search. (e.g.
entity metadata, documentation from TechDocs)
- It should be possible for any plugin to append relevant metadata to existing
content in search. (e.g. location (path) for TechDocs page)
- It should be easy to refine search queries (e.g. ranking, scoring, etc.)
- It should be easy to customize the search UI
- It should be easy to add search functionality to any Backstage plugin or
- It should be possible to refine search queries (e.g. ranking, scoring, etc.)
- It should be possible to customize the search UI
- It should be possible to add search functionality to any Backstage plugin or
deployment
Architecture non-goals:
- At this time, we do not intend to directly support event-driven or incremental
index management. Instead, we'll be focused on scheduled, bulk index
management.
+77 -6
View File
@@ -27,11 +27,15 @@ REPOSITORY_URL='https://github.com/org/repo'
git clone $REPOSITORY_URL
cd repo
# Install @techdocs/cli, mkdocs and mkdocs plugins
npm install -g @techdocs/cli
pip install mkdocs-techdocs-core==0.*
# Generate
npx @techdocs/cli generate
techdocs-cli generate --no-docker
# Publish
npx @techdocs/cli publish --publisher-type awsS3 --storage-name <bucket/container> --entity <Namespace/Kind/Name>
techdocs-cli publish --publisher-type awsS3 --storage-name <bucket/container> --entity <Namespace/Kind/Name>
```
That's it!
@@ -40,14 +44,16 @@ Take a look at
[`techdocs-cli` README](https://github.com/backstage/techdocs-cli) for the
complete command reference, details, and options.
## 1. Setup a workflow
## Steps
### 1. Setup a workflow
The TechDocs workflow should trigger on CI when any changes are made in the
repository containing the documentation files. You can be specific and configure
the workflow to be triggered only when files inside the `docs/` directory or
`mkdocs.yml` are changed.
## 2. Prepare step
### 2. Prepare step
The first step on the CI is to clone your documentation source repository in a
working directory. This is almost always the first step in most CI workflows.
@@ -62,7 +68,7 @@ step.
Eventually we are trying to do a `git clone <https://path/to/docs-repository/>`.
## 3. Generate step
### 3. Generate step
Install [`npx`](https://www.npmjs.com/package/npx) to use it for running
`techdocs-cli`. Or you can install using `npm install -g @techdocs/cli`.
@@ -78,7 +84,7 @@ npx @techdocs/cli generate --no-docker --source-dir PATH_TO_REPO --output-dir ./
`PATH_TO_REPO` should be the location in the file path where the prepare step
above clones the repository.
## 4. Publish step
### 4. Publish step
Depending on your cloud storage provider (AWS, Google Cloud, or Azure), set the
necessary authentication environment variables.
@@ -96,3 +102,68 @@ npx @techdocs/cli publish --publisher-type <awsS3|googleGcs> --storage-name <buc
The updated TechDocs site built in this workflow is now ready to be served by
the TechDocs plugin in your Backstage app.
## Example: GitHub Actions CI and AWS S3
Here is an example workflow using GitHub Actions CI and AWS S3 storage. You can
use any CI and any other
[TechDocs supported cloud storage providers](README.md#platforms-supported).
Add a `.github/workflows/techdocs.yml` file in your
[Software Template(s)](../software-templates/index.md) like this -
```yaml
name: Publish TechDocs Site
on:
push:
branches: [main]
# You can even set it to run only when TechDocs related files are updated.
# paths:
# - "docs/**"
# - "mkdocs.yml"
jobs:
publish-techdocs-site:
runs-on: ubuntu-latest
# The following secrets are required in your CI environment for publishing files to AWS S3.
# e.g. You can use GitHub Organization secrets to set them for all existing and new repositories.
env:
TECHDOCS_S3_BUCKET_NAME: ${{ secrets.TECHDOCS_S3_BUCKET_NAME }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
ENTITY_NAMESPACE: 'default'
ENTITY_KIND: 'Component'
ENTITY_NAME: 'my-doc-entity'
# In a Software template, Scaffolder will replace {{cookiecutter.component_id | jsonify}}
# with the correct entity name. This is same as metadata.name in the entity's catalog-info.yaml
# ENTITY_NAME: '{{ cookiecutter.component_id | jsonify }}'
steps:
- name: Checkout code
uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/setup-python@v2
- name: Install techdocs-cli
run: sudo npm install -g @techdocs/cli
- name: Install mkdocs and mkdocs plugins
run: python -m pip install mkdocs-techdocs-core==0.*
- name: Generate docs site
run: techdocs-cli generate --no-docker --verbose
- name: Publish docs site
run:
techdocs-cli publish --publisher-type awsS3 --storage-name
$TECHDOCS_S3_BUCKET_NAME --entity
$ENTITY_NAMESPACE/$ENTITY_KIND/$ENTITY_NAME
```
When the new repository is scaffolded or new documentation updates are
committed, the GitHub Action workflow will publish the TechDocs site, which can
be viewed in your Backstage app.
+8 -6
View File
@@ -157,15 +157,17 @@ techdocs:
builder: 'local'
```
Set `techdocs.builder` to `'local'` if you want your TechDocs Backend to be
responsible for generating documentation sites. If set to `'external'`,
Backstage will assume that the sites are being generated on each entity's CI/CD
pipeline, and are being stored in a storage somewhere.
Note that we recommend generating docs on CI/CD instead. Read more in the
"Basic" and "Recommended" sections of the
[TechDocs Architecture](architecture.md). But if you want to get started quickly
set `techdocs.builder` to `'local'` so that TechDocs Backend is responsible for
generating documentation sites. If set to `'external'`, Backstage will assume
that the sites are being generated on each entity's CI/CD pipeline, and are
being stored in a storage somewhere.
When `techdocs.builder` is set to `'external'`, TechDocs becomes more or less a
read-only experience where it serves static files from a storage containing all
the generated documentation. Read more in the "Basic" and "Recommended" sections
of the [TechDocs Architecture](architecture.md).
the generated documentation.
### Choosing storage (publisher)
+7 -5
View File
@@ -99,13 +99,15 @@ Are you missing a plugin for your favorite tool? Please
[suggest a new one](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME).
Chances are that someone will jump in and help build it.
### Community Initiatives 🧑‍🤝‍🧑 (Coming soon)
### Community Initiatives 🧑‍🤝‍🧑
- **Backstage Monthly Meetup** - A space for the community to come together to
share and learn about the latest happenings in Backstage.
- [**Backstage Community Sessions**](https://github.com/backstage/community#meetups) -
A monthly meetup for the community to come together to share and learn about
the latest happenings in Backstage.
- **Backstage Hackathons** - Open to everyone in our Backstage community, a
celebration of you, the project and building awesome things together
- **Backstage Hackathons** - (Coming soon) Open to everyone in our Backstage
community, a celebration of you, the project and building awesome things
together
### Completed milestones ✅
-8
View File
@@ -384,11 +384,3 @@ A frontend plugin that provides a page where the user can tweak various
settings.
Stability: `1`
### `welcome` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/welcome/)
A plugin that can be used to welcome the user to Backstage.
Stability: `0`. This used to be the start page for the example app, but has been
replaced by the catalog plugin. It is still viewable at `/welcome` but may be
removed.
+1 -1
View File
@@ -14,7 +14,7 @@ Here's a code sample:
import { createPlugin } from '@backstage/core';
export default createPlugin({
id: 'welcome',
id: 'plugin-name',
register({ featureFlags }) {
featureFlags.register('enable-example-feature');
},
+5 -5
View File
@@ -1,7 +1,7 @@
# AlertApi
The AlertApi type is defined at
[packages/core-api/src/apis/definitions/AlertApi.ts:29](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AlertApi.ts#L29).
[packages/core-api/src/apis/definitions/AlertApi.ts:29](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AlertApi.ts#L29).
The following Utility API implements this type: [alertApiRef](./README.md#alert)
@@ -38,7 +38,7 @@ export type AlertMessage = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/AlertApi.ts:19](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AlertApi.ts#L19).
[packages/core-api/src/apis/definitions/AlertApi.ts:19](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AlertApi.ts#L19).
Referenced by: [post](#post), [alert\$](#alert).
@@ -67,7 +67,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [alert\$](#alert).
@@ -86,7 +86,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -109,6 +109,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
+10 -10
View File
@@ -1,7 +1,7 @@
# AppThemeApi
The AppThemeApi type is defined at
[packages/core-api/src/apis/definitions/AppThemeApi.ts:56](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L56).
[packages/core-api/src/apis/definitions/AppThemeApi.ts:56](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AppThemeApi.ts#L56).
The following Utility API implements this type:
[appThemeApiRef](./README.md#apptheme)
@@ -81,7 +81,7 @@ export type AppTheme = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/AppThemeApi.ts:25](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L25).
[packages/core-api/src/apis/definitions/AppThemeApi.ts:25](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AppThemeApi.ts#L25).
Referenced by: [getInstalledThemes](#getinstalledthemes).
@@ -92,7 +92,7 @@ export type BackstagePalette = Palette &amp; <a href="#paletteadditions">Palette
</pre>
Defined at
[packages/theme/src/types.ts:74](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/theme/src/types.ts#L74).
[packages/theme/src/types.ts:74](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/theme/src/types.ts#L74).
Referenced by: [BackstageTheme](#backstagetheme).
@@ -107,7 +107,7 @@ export interface BackstageTheme extends Theme {
</pre>
Defined at
[packages/theme/src/types.ts:81](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/theme/src/types.ts#L81).
[packages/theme/src/types.ts:81](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/theme/src/types.ts#L81).
Referenced by: [AppTheme](#apptheme).
@@ -136,7 +136,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [activeThemeId\$](#activethemeid).
@@ -155,7 +155,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -170,7 +170,7 @@ export type PageTheme = {
</pre>
Defined at
[packages/theme/src/types.ts:103](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/theme/src/types.ts#L103).
[packages/theme/src/types.ts:103](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/theme/src/types.ts#L103).
Referenced by: [BackstageTheme](#backstagetheme).
@@ -183,7 +183,7 @@ export type PageThemeSelector = {
</pre>
Defined at
[packages/theme/src/types.ts:77](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/theme/src/types.ts#L77).
[packages/theme/src/types.ts:77](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/theme/src/types.ts#L77).
Referenced by: [BackstageTheme](#backstagetheme).
@@ -243,7 +243,7 @@ type PaletteAdditions = {
</pre>
Defined at
[packages/theme/src/types.ts:23](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/theme/src/types.ts#L23).
[packages/theme/src/types.ts:23](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/theme/src/types.ts#L23).
Referenced by: [BackstagePalette](#backstagepalette).
@@ -266,6 +266,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
@@ -1,7 +1,7 @@
# BackstageIdentityApi
The BackstageIdentityApi type is defined at
[packages/core-api/src/apis/definitions/auth.ts:134](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L134).
[packages/core-api/src/apis/definitions/auth.ts:134](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L134).
The following Utility APIs implement this type:
@@ -17,8 +17,12 @@ The following Utility APIs implement this type:
- [oauth2ApiRef](./README.md#oauth2)
- [oidcAuthApiRef](./README.md#oidcauth)
- [oktaAuthApiRef](./README.md#oktaauth)
- [oneloginAuthApiRef](./README.md#oneloginauth)
- [samlAuthApiRef](./README.md#samlauth)
## Members
@@ -70,7 +74,7 @@ export type AuthRequestOptions = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L40).
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L40).
Referenced by: [getBackstageIdentity](#getbackstageidentity).
@@ -79,7 +83,7 @@ Referenced by: [getBackstageIdentity](#getbackstageidentity).
<pre>
export type BackstageIdentity = {
/**
* The Backstage user ID.
* The backstage user ID.
*/
id: string;
@@ -91,6 +95,6 @@ export type BackstageIdentity = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:147](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L147).
[packages/core-api/src/apis/definitions/auth.ts:147](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L147).
Referenced by: [getBackstageIdentity](#getbackstageidentity).
+5 -5
View File
@@ -1,7 +1,7 @@
# Config
The Config type is defined at
[packages/config/src/types.ts:32](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/config/src/types.ts#L32).
[packages/config/src/types.ts:32](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/config/src/types.ts#L32).
The following Utility API implements this type:
[configApiRef](./README.md#config)
@@ -140,7 +140,7 @@ export type Config = {
</pre>
Defined at
[packages/config/src/types.ts:32](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/config/src/types.ts#L32).
[packages/config/src/types.ts:32](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/config/src/types.ts#L32).
Referenced by: [getConfig](#getconfig), [getOptionalConfig](#getoptionalconfig),
[getConfigArray](#getconfigarray),
@@ -153,7 +153,7 @@ export type JsonArray = <a href="#jsonvalue">JsonValue</a>[]
</pre>
Defined at
[packages/config/src/types.ts:18](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/config/src/types.ts#L18).
[packages/config/src/types.ts:18](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/config/src/types.ts#L18).
Referenced by: [JsonValue](#jsonvalue).
@@ -164,7 +164,7 @@ export type JsonObject = { [key in string]?: <a href="#jsonvalue">JsonValue</a>
</pre>
Defined at
[packages/config/src/types.ts:17](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/config/src/types.ts#L17).
[packages/config/src/types.ts:17](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/config/src/types.ts#L17).
Referenced by: [JsonValue](#jsonvalue).
@@ -181,7 +181,7 @@ export type JsonValue =
</pre>
Defined at
[packages/config/src/types.ts:19](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/config/src/types.ts#L19).
[packages/config/src/types.ts:19](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/config/src/types.ts#L19).
Referenced by: [get](#get), [getOptional](#getoptional),
[JsonObject](#jsonobject), [JsonArray](#jsonarray), [Config](#config).
+2 -2
View File
@@ -1,7 +1,7 @@
# DiscoveryApi
The DiscoveryApi type is defined at
[packages/core-api/src/apis/definitions/DiscoveryApi.ts:30](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L30).
[packages/core-api/src/apis/definitions/DiscoveryApi.ts:30](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L30).
The following Utility API implements this type:
[discoveryApiRef](./README.md#discovery)
@@ -12,7 +12,7 @@ The following Utility API implements this type:
Returns the HTTP base backend URL for a given plugin, without a trailing slash.
This method must always be called just before making a request. as opposed to
This method must always be called just before making a request, as opposed to
fetching the URL when constructing an API client. That is to ensure that more
flexible routing patterns can be supported.
+6 -6
View File
@@ -1,7 +1,7 @@
# ErrorApi
The ErrorApi type is defined at
[packages/core-api/src/apis/definitions/ErrorApi.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/ErrorApi.ts#L53).
[packages/core-api/src/apis/definitions/ErrorApi.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/ErrorApi.ts#L53).
The following Utility API implements this type: [errorApiRef](./README.md#error)
@@ -41,7 +41,7 @@ type Error = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/ErrorApi.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/ErrorApi.ts#L24).
[packages/core-api/src/apis/definitions/ErrorApi.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/ErrorApi.ts#L24).
Referenced by: [post](#post), [error\$](#error).
@@ -58,7 +58,7 @@ export type ErrorContext = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/ErrorApi.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/ErrorApi.ts#L33).
[packages/core-api/src/apis/definitions/ErrorApi.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/ErrorApi.ts#L33).
Referenced by: [post](#post), [error\$](#error).
@@ -87,7 +87,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [error\$](#error).
@@ -106,7 +106,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -129,6 +129,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
@@ -1,7 +1,7 @@
# FeatureFlagsApi
The FeatureFlagsApi type is defined at
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:60](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L60).
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:60](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L60).
The following Utility API implements this type:
[featureFlagsApiRef](./README.md#featureflags)
@@ -68,7 +68,7 @@ export type FeatureFlag = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:31](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L31).
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:31](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L31).
Referenced by: [registerFlag](#registerflag),
[getRegisteredFlags](#getregisteredflags).
@@ -83,7 +83,7 @@ export enum FeatureFlagState {
</pre>
Defined at
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:36](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L36).
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:36](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L36).
Referenced by: [FeatureFlagsSaveOptions](#featureflagssaveoptions).
@@ -108,6 +108,6 @@ export type FeatureFlagsSaveOptions = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:44](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L44).
[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:44](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L44).
Referenced by: [save](#save).
+2 -2
View File
@@ -1,7 +1,7 @@
# IdentityApi
The IdentityApi type is defined at
[packages/core-api/src/apis/definitions/IdentityApi.ts:22](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/IdentityApi.ts#L22).
[packages/core-api/src/apis/definitions/IdentityApi.ts:22](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/IdentityApi.ts#L22).
The following Utility API implements this type:
[identityApiRef](./README.md#identity)
@@ -76,6 +76,6 @@ export type ProfileInfo = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:162](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L162).
[packages/core-api/src/apis/definitions/auth.ts:162](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L162).
Referenced by: [getProfile](#getprofile).
+7 -3
View File
@@ -1,7 +1,7 @@
# OAuthApi
The OAuthApi type is defined at
[packages/core-api/src/apis/definitions/auth.ts:67](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L67).
[packages/core-api/src/apis/definitions/auth.ts:67](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L67).
The following Utility APIs implement this type:
@@ -15,8 +15,12 @@ The following Utility APIs implement this type:
- [oauth2ApiRef](./README.md#oauth2)
- [oidcAuthApiRef](./README.md#oidcauth)
- [oktaAuthApiRef](./README.md#oktaauth)
- [oneloginAuthApiRef](./README.md#oneloginauth)
## Members
### getAccessToken()
@@ -82,7 +86,7 @@ export type AuthRequestOptions = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L40).
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L40).
Referenced by: [getAccessToken](#getaccesstoken).
@@ -108,6 +112,6 @@ export type OAuthScope = string | string[]
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:38](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L38).
[packages/core-api/src/apis/definitions/auth.ts:38](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L38).
Referenced by: [getAccessToken](#getaccesstoken).
@@ -1,7 +1,7 @@
# OAuthRequestApi
The OAuthRequestApi type is defined at
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:99](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L99).
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:99](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L99).
The following Utility API implements this type:
[oauthRequestApiRef](./README.md#oauthrequest)
@@ -73,7 +73,7 @@ export type AuthProvider = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:27](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L27).
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:27](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L27).
Referenced by: [AuthRequesterOptions](#authrequesteroptions),
[PendingAuthRequest](#pendingauthrequest).
@@ -97,7 +97,7 @@ export type AuthRequester&lt;AuthResponse&gt; = (
</pre>
Defined at
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:66](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L66).
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:66](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L66).
Referenced by: [createAuthRequester](#createauthrequester).
@@ -122,7 +122,7 @@ export type AuthRequesterOptions&lt;AuthResponse&gt; = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:43](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L43).
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:43](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L43).
Referenced by: [createAuthRequester](#createauthrequester).
@@ -151,7 +151,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [authRequest\$](#authrequest).
@@ -170,7 +170,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -205,7 +205,7 @@ export type PendingAuthRequest = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:77](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L77).
[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:77](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L77).
Referenced by: [authRequest\$](#authrequest).
@@ -228,6 +228,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
@@ -1,7 +1,7 @@
# OpenIdConnectApi
The OpenIdConnectApi type is defined at
[packages/core-api/src/apis/definitions/auth.ts:99](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L99).
[packages/core-api/src/apis/definitions/auth.ts:99](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L99).
The following Utility APIs implement this type:
@@ -13,8 +13,12 @@ The following Utility APIs implement this type:
- [oauth2ApiRef](./README.md#oauth2)
- [oidcAuthApiRef](./README.md#oidcauth)
- [oktaAuthApiRef](./README.md#oktaauth)
- [oneloginAuthApiRef](./README.md#oneloginauth)
## Members
### getIdToken()
@@ -66,6 +70,6 @@ export type AuthRequestOptions = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L40).
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L40).
Referenced by: [getIdToken](#getidtoken).
@@ -1,7 +1,7 @@
# ProfileInfoApi
The ProfileInfoApi type is defined at
[packages/core-api/src/apis/definitions/auth.ts:117](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L117).
[packages/core-api/src/apis/definitions/auth.ts:117](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L117).
The following Utility APIs implement this type:
@@ -17,8 +17,12 @@ The following Utility APIs implement this type:
- [oauth2ApiRef](./README.md#oauth2)
- [oidcAuthApiRef](./README.md#oidcauth)
- [oktaAuthApiRef](./README.md#oktaauth)
- [oneloginAuthApiRef](./README.md#oneloginauth)
- [samlAuthApiRef](./README.md#samlauth)
## Members
@@ -67,7 +71,7 @@ export type AuthRequestOptions = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L40).
[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L40).
Referenced by: [getProfile](#getprofile).
@@ -95,6 +99,6 @@ export type ProfileInfo = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:162](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L162).
[packages/core-api/src/apis/definitions/auth.ts:162](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L162).
Referenced by: [getProfile](#getprofile).
+41 -17
View File
@@ -12,7 +12,7 @@ Used to report alerts and forward them to the app
Implemented type: [AlertApi](./AlertApi.md)
ApiRef:
[alertApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AlertApi.ts#L41)
[alertApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AlertApi.ts#L41)
### appTheme
@@ -21,7 +21,7 @@ API Used to configure the app theme, and enumerate options
Implemented type: [AppThemeApi](./AppThemeApi.md)
ApiRef:
[appThemeApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L80)
[appThemeApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/AppThemeApi.ts#L80)
### auth0Auth
@@ -32,7 +32,7 @@ Implemented types: [OpenIdConnectApi](./OpenIdConnectApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[auth0AuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L275)
[auth0AuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L275)
### config
@@ -41,7 +41,7 @@ Used to access runtime configuration
Implemented type: [Config](./Config.md)
ApiRef:
[configApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/ConfigApi.ts#L22)
[configApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/ConfigApi.ts#L25)
### discovery
@@ -50,7 +50,7 @@ Provides service discovery of backend plugins
Implemented type: [DiscoveryApi](./DiscoveryApi.md)
ApiRef:
[discoveryApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L44)
[discoveryApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L44)
### error
@@ -59,7 +59,7 @@ Used to report errors and forward them to the app
Implemented type: [ErrorApi](./ErrorApi.md)
ApiRef:
[errorApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/ErrorApi.ts#L65)
[errorApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/ErrorApi.ts#L65)
### featureFlags
@@ -68,7 +68,7 @@ Used to toggle functionality in features across Backstage
Implemented type: [FeatureFlagsApi](./FeatureFlagsApi.md)
ApiRef:
[featureFlagsApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L83)
[featureFlagsApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L83)
### githubAuth
@@ -79,7 +79,7 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[githubAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L232)
[githubAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L232)
### gitlabAuth
@@ -90,7 +90,7 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[gitlabAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L262)
[gitlabAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L262)
### googleAuth
@@ -102,7 +102,7 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[googleAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L215)
[googleAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L215)
### identity
@@ -111,7 +111,7 @@ Provides access to the identity of the signed in user
Implemented type: [IdentityApi](./IdentityApi.md)
ApiRef:
[identityApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/IdentityApi.ts#L54)
[identityApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/IdentityApi.ts#L53)
### microsoftAuth
@@ -123,7 +123,7 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[microsoftAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L289)
[microsoftAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L289)
### oauth2
@@ -135,7 +135,7 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[oauth2ApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L303)
[oauth2ApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L303)
### oauthRequest
@@ -144,7 +144,19 @@ An API for implementing unified OAuth flows in Backstage
Implemented type: [OAuthRequestApi](./OAuthRequestApi.md)
ApiRef:
[oauthRequestApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L130)
[oauthRequestApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L130)
### oidcAuth
Example of how to use oidc custom provider
Implemented types: [OAuthApi](./OAuthApi.md),
[OpenIdConnectApi](./OpenIdConnectApi.md),
[ProfileInfoApi](./ProfileInfoApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[oidcAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L317)
### oktaAuth
@@ -156,7 +168,19 @@ Implemented types: [OAuthApi](./OAuthApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[oktaAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L245)
[oktaAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L245)
### oneloginAuth
Provides authentication towards OneLogin APIs and identities
Implemented types: [OAuthApi](./OAuthApi.md),
[OpenIdConnectApi](./OpenIdConnectApi.md),
[ProfileInfoApi](./ProfileInfoApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[oneloginAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L338)
### samlAuth
@@ -166,7 +190,7 @@ Implemented types: [ProfileInfoApi](./ProfileInfoApi.md),
[BackstageIdentityApi](./BackstageIdentityApi.md), [SessionApi](./SessionApi.md)
ApiRef:
[samlAuthApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L317)
[samlAuthApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L331)
### storage
@@ -175,4 +199,4 @@ Provides the ability to store data which is unique to the user
Implemented type: [StorageApi](./StorageApi.md)
ApiRef:
[storageApiRef](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/StorageApi.ts#L68)
[storageApiRef](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/StorageApi.ts#L68)
+9 -5
View File
@@ -1,7 +1,7 @@
# SessionApi
The SessionApi type is defined at
[packages/core-api/src/apis/definitions/auth.ts:190](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L190).
[packages/core-api/src/apis/definitions/auth.ts:190](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L190).
The following Utility APIs implement this type:
@@ -17,8 +17,12 @@ The following Utility APIs implement this type:
- [oauth2ApiRef](./README.md#oauth2)
- [oidcAuthApiRef](./README.md#oidcauth)
- [oktaAuthApiRef](./README.md#oktaauth)
- [oneloginAuthApiRef](./README.md#oneloginauth)
- [samlAuthApiRef](./README.md#samlauth)
## Members
@@ -77,7 +81,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [sessionState\$](#sessionstate).
@@ -96,7 +100,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -112,7 +116,7 @@ export enum SessionState {
</pre>
Defined at
[packages/core-api/src/apis/definitions/auth.ts:182](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/auth.ts#L182).
[packages/core-api/src/apis/definitions/auth.ts:182](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/auth.ts#L182).
Referenced by: [sessionState\$](#sessionstate).
@@ -135,6 +139,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
+6 -6
View File
@@ -1,7 +1,7 @@
# StorageApi
The StorageApi type is defined at
[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/StorageApi.ts#L31).
[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/StorageApi.ts#L31).
The following Utility API implements this type:
[storageApiRef](./README.md#storage)
@@ -79,7 +79,7 @@ export type Observable&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L53).
[packages/core-api/src/types.ts:53](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L53).
Referenced by: [observe\$](#observe), [StorageApi](#storageapi).
@@ -98,7 +98,7 @@ export type Observer&lt;T&gt; = {
</pre>
Defined at
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L24).
[packages/core-api/src/types.ts:24](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L24).
Referenced by: [Observable](#observable).
@@ -144,7 +144,7 @@ export interface StorageApi {
</pre>
Defined at
[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/StorageApi.ts#L31).
[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/StorageApi.ts#L31).
Referenced by: [forBucket](#forbucket).
@@ -158,7 +158,7 @@ export type StorageValueChange&lt;T = any&gt; = {
</pre>
Defined at
[packages/core-api/src/apis/definitions/StorageApi.ts:21](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/apis/definitions/StorageApi.ts#L21).
[packages/core-api/src/apis/definitions/StorageApi.ts:21](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/apis/definitions/StorageApi.ts#L21).
Referenced by: [observe\$](#observe), [StorageApi](#storageapi).
@@ -181,6 +181,6 @@ export type Subscription = {
</pre>
Defined at
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/ca535f2f66c3a4980c80f4b1a049dfd07569010e/packages/core-api/src/types.ts#L33).
[packages/core-api/src/types.ts:33](https://github.com/backstage/backstage/blob/a4dbd8353cfa4d4d4334473e2c33afcda64e130d/packages/core-api/src/types.ts#L33).
Referenced by: [Observable](#observable).
+4
View File
@@ -1115,6 +1115,10 @@ code {
font-size: 115%;
}
.post pre {
color: #e4e4e4;
}
.Block__GIF {
width: 190px;
height: auto;
+86
View File
@@ -1,5 +1,91 @@
# example-app
## 0.2.15
### Patch Changes
- 07bafa248: Add configurable `scope` for oauth2 auth provider.
Some OAuth2 providers require certain scopes to facilitate a user sign-in using the Authorization Code flow.
This change adds the optional `scope` key to auth.providers.oauth2. An example is:
```yaml
auth:
providers:
oauth2:
development:
clientId:
$env: DEV_OAUTH2_CLIENT_ID
clientSecret:
$env: DEV_OAUTH2_CLIENT_SECRET
authorizationUrl:
$env: DEV_OAUTH2_AUTH_URL
tokenUrl:
$env: DEV_OAUTH2_TOKEN_URL
scope: saml-login-selector openid profile email
```
This tells the OAuth 2.0 AS to perform a SAML login and return OIDC information include the `profile`
and `email` claims as part of the ID Token.
- Updated dependencies [753bb4c40]
- Updated dependencies [6ed2b47d6]
- Updated dependencies [b33fa4cf4]
- Updated dependencies [d36660721]
- Updated dependencies [6b26c9f41]
- Updated dependencies [b3f0c3811]
- Updated dependencies [302795d10]
- Updated dependencies [9ec66c345]
- Updated dependencies [53d3e2d62]
- Updated dependencies [ca559171b]
- Updated dependencies [53348f0af]
- Updated dependencies [f5e564cd6]
- Updated dependencies [68dd79d83]
- Updated dependencies [29a138636]
- Updated dependencies [14aef4b94]
- Updated dependencies [41af18227]
- Updated dependencies [1df75733e]
- Updated dependencies [02d6803e8]
- Updated dependencies [b288a291e]
- Updated dependencies [025c0c7bf]
- Updated dependencies [e5da858d7]
- Updated dependencies [9230d07e7]
- Updated dependencies [f5f45744e]
- Updated dependencies [0fe8ff5be]
- Updated dependencies [c5ab91ce3]
- Updated dependencies [64b9efac2]
- Updated dependencies [19d354c78]
- Updated dependencies [7716d1d70]
- Updated dependencies [8f3443427]
- Updated dependencies [b51ee6ece]
- Updated dependencies [accdfeb30]
- Updated dependencies [804502a5c]
- @backstage/plugin-catalog-import@0.4.0
- @backstage/plugin-catalog@0.3.1
- @backstage/plugin-kubernetes@0.3.9
- @backstage/plugin-rollbar@0.3.0
- @backstage/plugin-scaffolder@0.5.0
- @backstage/plugin-cost-insights@0.8.1
- @backstage/plugin-circleci@0.2.8
- @backstage/plugin-search@0.3.0
- @backstage/plugin-cloudbuild@0.2.9
- @backstage/plugin-register-component@0.2.9
- @backstage/plugin-sentry@0.3.5
- @backstage/plugin-jenkins@0.3.9
- @backstage/plugin-api-docs@0.4.5
- @backstage/plugin-lighthouse@0.2.10
- @backstage/plugin-techdocs@0.5.6
- @backstage/plugin-pagerduty@0.2.8
- @backstage/plugin-org@0.3.6
- @backstage/plugin-github-actions@0.3.2
- @backstage/plugin-explore@0.2.5
- @backstage/plugin-newrelic@0.2.5
- @backstage/plugin-catalog-react@0.0.3
- @backstage/plugin-kafka@0.2.2
- @backstage/core@0.6.1
- @backstage/plugin-gitops-profiles@0.2.5
- @backstage/plugin-tech-radar@0.3.5
## 0.2.14
### Patch Changes
+27 -28
View File
@@ -1,40 +1,39 @@
{
"name": "example-app",
"version": "0.2.14",
"version": "0.2.15",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/catalog-model": "^0.7.1",
"@backstage/cli": "^0.6.0",
"@backstage/core": "^0.6.0",
"@backstage/plugin-api-docs": "^0.4.4",
"@backstage/plugin-catalog": "^0.3.0",
"@backstage/plugin-catalog-react": "^0.0.2",
"@backstage/plugin-catalog-import": "^0.3.7",
"@backstage/plugin-circleci": "^0.2.7",
"@backstage/plugin-cloudbuild": "^0.2.8",
"@backstage/plugin-cost-insights": "^0.8.0",
"@backstage/plugin-explore": "^0.2.4",
"@backstage/core": "^0.6.1",
"@backstage/plugin-api-docs": "^0.4.5",
"@backstage/plugin-catalog": "^0.3.1",
"@backstage/plugin-catalog-react": "^0.0.3",
"@backstage/plugin-catalog-import": "^0.4.0",
"@backstage/plugin-circleci": "^0.2.8",
"@backstage/plugin-cloudbuild": "^0.2.9",
"@backstage/plugin-cost-insights": "^0.8.1",
"@backstage/plugin-explore": "^0.2.5",
"@backstage/plugin-gcp-projects": "^0.2.4",
"@backstage/plugin-github-actions": "^0.3.1",
"@backstage/plugin-gitops-profiles": "^0.2.4",
"@backstage/plugin-github-actions": "^0.3.2",
"@backstage/plugin-gitops-profiles": "^0.2.5",
"@backstage/plugin-graphiql": "^0.2.7",
"@backstage/plugin-org": "^0.3.5",
"@backstage/plugin-jenkins": "^0.3.8",
"@backstage/plugin-kafka": "^0.2.1",
"@backstage/plugin-kubernetes": "^0.3.8",
"@backstage/plugin-lighthouse": "^0.2.9",
"@backstage/plugin-newrelic": "^0.2.4",
"@backstage/plugin-pagerduty": "0.2.7",
"@backstage/plugin-register-component": "^0.2.8",
"@backstage/plugin-rollbar": "^0.2.9",
"@backstage/plugin-scaffolder": "^0.4.2",
"@backstage/plugin-sentry": "^0.3.4",
"@backstage/plugin-search": "^0.2.7",
"@backstage/plugin-tech-radar": "^0.3.4",
"@backstage/plugin-techdocs": "^0.5.5",
"@backstage/plugin-org": "^0.3.6",
"@backstage/plugin-jenkins": "^0.3.9",
"@backstage/plugin-kafka": "^0.2.2",
"@backstage/plugin-kubernetes": "^0.3.9",
"@backstage/plugin-lighthouse": "^0.2.10",
"@backstage/plugin-newrelic": "^0.2.5",
"@backstage/plugin-pagerduty": "0.2.8",
"@backstage/plugin-register-component": "^0.2.9",
"@backstage/plugin-rollbar": "^0.3.0",
"@backstage/plugin-scaffolder": "^0.5.0",
"@backstage/plugin-sentry": "^0.3.5",
"@backstage/plugin-search": "^0.3.0",
"@backstage/plugin-tech-radar": "^0.3.5",
"@backstage/plugin-techdocs": "^0.5.6",
"@backstage/plugin-user-settings": "^0.2.5",
"@backstage/plugin-welcome": "^0.2.5",
"@backstage/theme": "^0.2.3",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
@@ -54,7 +53,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/test-utils": "^0.1.6",
"@backstage/test-utils": "^0.1.7",
"@testing-library/cypress": "^7.0.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
+2 -5
View File
@@ -23,7 +23,7 @@ import {
SignInPage,
} from '@backstage/core';
import { Router as CatalogRouter } from '@backstage/plugin-catalog';
import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import';
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
import { ExplorePage } from '@backstage/plugin-explore';
import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql';
import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse';
@@ -69,10 +69,7 @@ const catalogRouteRef = createRouteRef({
const routes = (
<FlatRoutes>
<Navigate key="/" to="/catalog" />
<Route
path="/catalog-import"
element={<ImportComponentRouter catalogRouteRef={catalogRouteRef} />}
/>
<Route path="/catalog-import" element={<CatalogImportPage />} />
<Route
path={`${catalogRouteRef.path}`}
element={<CatalogRouter EntityPage={EntityPage} />}
@@ -28,7 +28,11 @@ import {
ProvidedApisCard,
ProvidingComponentsCard,
} from '@backstage/plugin-api-docs';
import { AboutCard, EntityPageLayout } from '@backstage/plugin-catalog';
import {
AboutCard,
EntityLinksCard,
EntityPageLayout,
} from '@backstage/plugin-catalog';
import { useEntity } from '@backstage/plugin-catalog-react';
import {
isPluginApplicableToEntity as isCircleCIAvailable,
@@ -177,6 +181,9 @@ const ComponentOverviewContent = ({ entity }: { entity: Entity }) => (
<PagerDutyCard entity={entity} />
</Grid>
)}
<Grid item md={4} sm={6}>
<EntityLinksCard entity={entity} />
</Grid>
<RecentCICDRunsSwitcher entity={entity} />
{isGitHubAvailable(entity) && (
<>
+7
View File
@@ -22,6 +22,7 @@ import {
samlAuthApiRef,
microsoftAuthApiRef,
oneloginAuthApiRef,
oauth2ApiRef,
oidcAuthApiRef,
} from '@backstage/core';
@@ -32,6 +33,12 @@ export const providers = [
message: 'Sign In using OpenId Connect',
apiRef: oidcAuthApiRef,
},
{
id: 'oauth2-auth-provider',
title: 'OAuth 2.0',
message: 'Sign In using OAuth 2.0',
apiRef: oauth2ApiRef,
},
{
id: 'google-auth-provider',
title: 'Google',
-1
View File
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { plugin as WelcomePlugin } from '@backstage/plugin-welcome';
export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse';
export { plugin as CatalogPlugin } from '@backstage/plugin-catalog';
export { plugin as ScaffolderPlugin } from '@backstage/plugin-scaffolder';
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-common
## 0.5.3
### Patch Changes
- ffffea8e6: Minor updates to reflect the changes in `@backstage/integration` that made the fields `apiBaseUrl` and `apiUrl` mandatory.
- 82b2c11b6: Set explicit content-type in error handler responses.
- 965e200c6: Slight refactoring in support of a future search implementation in `UrlReader`. Mostly moving code around.
- 5a5163519: Implement `UrlReader.search` which implements glob matching.
- Updated dependencies [ffffea8e6]
- @backstage/integration@0.4.0
## 0.5.2
### Patch Changes
+4 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.5.2",
"version": "0.5.3",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -32,7 +32,7 @@
"@backstage/cli-common": "^0.1.1",
"@backstage/config": "^0.1.2",
"@backstage/config-loader": "^0.5.1",
"@backstage/integration": "^0.3.2",
"@backstage/integration": "^0.4.0",
"@octokit/rest": "^18.0.12",
"@types/cors": "^2.8.6",
"@types/express": "^4.17.6",
@@ -50,6 +50,7 @@
"knex": "^0.21.6",
"lodash": "^4.17.15",
"logform": "^2.1.1",
"minimatch": "^3.0.4",
"minimist": "^1.2.5",
"morgan": "^1.10.0",
"selfsigned": "^1.10.7",
@@ -68,7 +69,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.6.0",
"@backstage/test-utils": "^0.1.5",
"@backstage/test-utils": "^0.1.7",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
@@ -63,10 +63,10 @@ export function errorHandler(
return (
error: Error,
_request: Request,
response: Response,
res: Response,
next: NextFunction,
) => {
if (response.headersSent) {
if (res.headersSent) {
// If the headers have already been sent, do not send the response again
// as this will throw an error in the backend.
next(error);
@@ -80,7 +80,9 @@ export function errorHandler(
logger.error(error);
}
response.status(status).send(message);
res.status(status);
res.setHeader('content-type', 'text/plain');
res.send(message);
};
}
@@ -29,6 +29,7 @@ import {
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,
SearchResponse,
UrlReader,
} from './types';
import { ReadTreeResponseFactory } from './tree';
@@ -116,6 +117,10 @@ export class AzureUrlReader implements UrlReader {
});
}
async search(): Promise<SearchResponse> {
throw new Error('AzureUrlReader does not implement search');
}
toString() {
const { host, token } = this.options;
return `azure{host=${host},authed=${Boolean(token)}}`;
@@ -31,6 +31,7 @@ import {
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,
SearchResponse,
UrlReader,
} from './types';
@@ -129,6 +130,10 @@ export class BitbucketUrlReader implements UrlReader {
});
}
async search(): Promise<SearchResponse> {
throw new Error('BitbucketUrlReader does not implement search');
}
toString() {
const { host, token, username, appPassword } = this.config;
let authed = Boolean(token);
@@ -16,7 +16,12 @@
import fetch from 'cross-fetch';
import { NotFoundError } from '../errors';
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
import {
ReaderFactory,
ReadTreeResponse,
SearchResponse,
UrlReader,
} from './types';
/**
* A UrlReader that does a plain fetch of the URL.
@@ -68,10 +73,14 @@ export class FetchUrlReader implements UrlReader {
throw new Error(message);
}
readTree(): Promise<ReadTreeResponse> {
async readTree(): Promise<ReadTreeResponse> {
throw new Error('FetchUrlReader does not implement readTree');
}
async search(): Promise<SearchResponse> {
throw new Error('FetchUrlReader does not implement search');
}
toString() {
return 'fetch{}';
}
@@ -23,7 +23,13 @@ import { rest } from 'msw';
import { setupServer } from 'msw/node';
import path from 'path';
import { NotFoundError, NotModifiedError } from '../errors';
import { GithubUrlReader } from './GithubUrlReader';
import {
GhBlobResponse,
GhBranchResponse,
GhRepoResponse,
GhTreeResponse,
GithubUrlReader,
} from './GithubUrlReader';
import { ReadTreeResponseFactory } from './tree';
const treeResponseFactory = ReadTreeResponseFactory.create({
@@ -69,6 +75,10 @@ describe('GithubUrlReader', () => {
});
});
/*
* read
*/
describe('read', () => {
it('should use the headers from the credentials provider to the fetch request when doing read', async () => {
expect.assertions(2);
@@ -107,6 +117,10 @@ describe('GithubUrlReader', () => {
});
});
/*
* readTree
*/
describe('readTree', () => {
beforeEach(() => {
mockFs({
@@ -128,29 +142,31 @@ describe('GithubUrlReader', () => {
);
const reposGithubApiResponse = {
id: '123',
id: 123,
full_name: 'backstage/mock',
default_branch: 'main',
branches_url:
'https://api.github.com/repos/backstage/mock/branches{/branch}',
archive_url:
'https://api.github.com/repos/backstage/mock/{archive_format}{/ref}',
};
} as Partial<GhRepoResponse>;
const reposGheApiResponse = {
...reposGithubApiResponse,
id: 123,
full_name: 'backstage/mock',
default_branch: 'main',
branches_url:
'https://ghe.github.com/api/v3/repos/backstage/mock/branches{/branch}',
archive_url:
'https://ghe.github.com/api/v3/repos/backstage/mock/{archive_format}{/ref}',
};
} as Partial<GhRepoResponse>;
const branchesApiResponse = {
name: 'main',
commit: {
sha: 'etag123abc',
},
};
} as Partial<GhBranchResponse>;
beforeEach(() => {
worker.use(
@@ -392,4 +408,359 @@ describe('GithubUrlReader', () => {
}).toThrowError('must configure an explicit apiBaseUrl');
});
});
/*
* search
*/
describe('search', () => {
beforeEach(() => {
mockFs({ '/tmp': mockFs.directory() });
});
afterEach(() => {
mockFs.restore();
});
const repoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'backstage-mock-etag123.tar.gz',
),
);
const githubTreeContents: GhTreeResponse['tree'] = [
{
path: 'mkdocs.yml',
type: 'blob',
url: 'https://api.github.com/repos/backstage/mock/git/blobs/1',
},
{
path: 'docs',
type: 'tree',
url: 'https://api.github.com/repos/backstage/mock/git/trees/2',
},
{
path: 'docs/index.md',
type: 'blob',
url: 'https://api.github.com/repos/backstage/mock/git/blobs/3',
},
];
const gheTreeContents: GhTreeResponse['tree'] = [
{
path: 'mkdocs.yml',
type: 'blob',
url: 'https://ghe.github.com/api/v3/repos/backstage/mock/git/blobs/1',
},
{
path: 'docs',
type: 'tree',
url: 'https://ghe.github.com/api/v3/repos/backstage/mock/git/trees/2',
},
{
path: 'docs/index.md',
type: 'blob',
url: 'https://ghe.github.com/api/v3/repos/backstage/mock/git/blobs/3',
},
];
// Tarballs
beforeEach(() => {
worker.use(
rest.get(
'https://api.github.com/repos/backstage/mock/tarball/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/x-gzip'),
ctx.set(
'content-disposition',
'attachment; filename=backstage-mock-etag123.tar.gz',
),
ctx.body(repoBuffer),
),
),
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/tarball/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/x-gzip'),
ctx.set(
'content-disposition',
'attachment; filename=backstage-mock-etag123.tar.gz',
),
ctx.body(repoBuffer),
),
),
);
});
// Repo details
beforeEach(() => {
const githubResponse = {
id: 123,
full_name: 'backstage/mock',
default_branch: 'main',
branches_url:
'https://api.github.com/repos/backstage/mock/branches{/branch}',
archive_url:
'https://api.github.com/repos/backstage/mock/{archive_format}{/ref}',
trees_url:
'https://api.github.com/repos/backstage/mock/git/trees{/sha}',
} as Partial<GhRepoResponse>;
const gheResponse = {
id: 123,
full_name: 'backstage/mock',
default_branch: 'main',
branches_url:
'https://ghe.github.com/api/v3/repos/backstage/mock/branches{/branch}',
archive_url:
'https://ghe.github.com/api/v3/repos/backstage/mock/{archive_format}{/ref}',
trees_url:
'https://ghe.github.com/api/v3/repos/backstage/mock/git/trees{/sha}',
} as Partial<GhRepoResponse>;
worker.use(
rest.get('https://api.github.com/repos/backstage/mock', (_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(githubResponse),
),
),
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(gheResponse),
),
),
);
});
// Branch details
beforeEach(() => {
const response = {
name: 'main',
commit: {
sha: 'etag123abc',
},
} as Partial<GhBranchResponse>;
worker.use(
rest.get(
'https://api.github.com/repos/backstage/mock/branches/main',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(response),
),
),
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/branches/main',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(response),
),
),
rest.get(
'https://api.github.com/repos/backstage/mock/branches/branchDoesNotExist',
(_, res, ctx) => res(ctx.status(404)),
),
);
});
// Blobs
beforeEach(() => {
const blob1Response = {
content: Buffer.from('site_name: Test\n').toString('base64'),
} as Partial<GhBlobResponse>;
const blob3Response = {
content: Buffer.from('# Test\n').toString('base64'),
} as Partial<GhBlobResponse>;
worker.use(
rest.get(
'https://api.github.com/repos/backstage/mock/git/blobs/1',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(blob1Response),
),
),
rest.get(
'https://api.github.com/repos/backstage/mock/git/blobs/3',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(blob3Response),
),
),
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/git/blobs/1',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(blob1Response),
),
),
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/git/blobs/3',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json(blob3Response),
),
),
);
});
async function runTests(reader: GithubUrlReader, baseUrl: string) {
const r1 = await reader.search(
`${baseUrl}/backstage/mock/tree/main/**/*`,
);
expect(r1.etag).toBe('etag123abc');
expect(r1.files.length).toBe(2);
const r2 = await reader.search(
`${baseUrl}/backstage/mock/tree/main/**/*`,
{ etag: 'somethingElse' },
);
expect(r2.etag).toBe('etag123abc');
expect(r2.files.length).toBe(2);
const r3 = await reader.search(`${baseUrl}/backstage/mock/tree/main/o`);
expect(r3.files.length).toBe(0);
const r4 = await reader.search(
`${baseUrl}/backstage/mock/tree/main/*docs*`,
);
expect(r4.files.length).toBe(1);
expect(r4.files[0].url).toBe(
`${baseUrl}/backstage/mock/tree/main/mkdocs.yml`,
);
await expect(r4.files[0].content()).resolves.toEqual(
Buffer.from('site_name: Test\n'),
);
const r5 = await reader.search(
`${baseUrl}/backstage/mock/tree/main/*/index.*`,
);
expect(r5.files.length).toBe(1);
expect(r5.files[0].url).toBe(
`${baseUrl}/backstage/mock/tree/main/docs/index.md`,
);
await expect(r5.files[0].content()).resolves.toEqual(
Buffer.from('# Test\n'),
);
}
// eslint-disable-next-line jest/expect-expect
it('succeeds on github when going via repo listing', async () => {
worker.use(
rest.get(
'https://api.github.com/repos/backstage/mock/git/trees/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json({
truncated: false,
tree: githubTreeContents,
} as Partial<GhTreeResponse>),
),
),
);
await runTests(githubProcessor, 'https://github.com');
});
// eslint-disable-next-line jest/expect-expect
it('succeeds on github when going via readTree', async () => {
worker.use(
rest.get(
'https://api.github.com/repos/backstage/mock/git/trees/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json({
truncated: true,
tree: [],
} as Partial<GhTreeResponse>),
),
),
);
await runTests(githubProcessor, 'https://github.com');
});
// eslint-disable-next-line jest/expect-expect
it('succeeds on ghe when going via repo listing', async () => {
worker.use(
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/git/trees/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json({
truncated: false,
tree: gheTreeContents,
} as Partial<GhTreeResponse>),
),
),
);
await runTests(gheProcessor, 'https://ghe.github.com');
});
// eslint-disable-next-line jest/expect-expect
it('succeeds on ghe when going via readTree', async () => {
worker.use(
rest.get(
'https://ghe.github.com/api/v3/repos/backstage/mock/git/trees/etag123abc',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('Content-Type', 'application/json'),
ctx.json({
truncated: true,
tree: [],
} as Partial<GhTreeResponse>),
),
),
);
await runTests(gheProcessor, 'https://ghe.github.com');
});
it('throws NotModifiedError when same etag', async () => {
await expect(
githubProcessor.search(
'https://githib.com/backstage/mock/tree/main/**/*',
{ etag: 'etag123abc' },
),
).rejects.toThrow(NotModifiedError);
});
it('throws NotFoundError when missing branch', async () => {
await expect(
githubProcessor.search(
'https://githib.com/backstage/mock/tree/branchDoesNotExist/**/*',
),
).rejects.toThrow(NotFoundError);
});
});
});
@@ -23,6 +23,7 @@ import {
import { RestEndpointMethodTypes } from '@octokit/rest';
import fetch from 'cross-fetch';
import parseGitUrl from 'git-url-parse';
import { Minimatch } from 'minimatch';
import { Readable } from 'stream';
import { NotFoundError, NotModifiedError } from '../errors';
import { ReadTreeResponseFactory } from './tree';
@@ -30,9 +31,17 @@ import {
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,
SearchOptions,
SearchResponse,
SearchResponseFile,
UrlReader,
} from './types';
export type GhRepoResponse = RestEndpointMethodTypes['repos']['get']['response']['data'];
export type GhBranchResponse = RestEndpointMethodTypes['repos']['getBranch']['response']['data'];
export type GhTreeResponse = RestEndpointMethodTypes['git']['getTree']['response']['data'];
export type GhBlobResponse = RestEndpointMethodTypes['git']['getBlob']['response']['data'];
/**
* A processor that adds the ability to read files from GitHub v3 APIs, such as
* the one exposed by GitHub itself.
@@ -106,27 +115,43 @@ export class GithubUrlReader implements UrlReader {
throw new NotModifiedError();
}
const { filepath } = parseGitUrl(url);
const { headers } = await this.deps.credentialsProvider.getCredentials({
url,
});
// archive_url looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}"
const archive = await this.fetchResponse(
repoDetails.repo.archive_url
.replace('{archive_format}', 'tarball')
.replace('{/ref}', `/${commitSha}`),
return this.doReadTree(
repoDetails.repo.archive_url,
commitSha,
filepath,
{ headers },
options,
);
}
async search(url: string, options?: SearchOptions): Promise<SearchResponse> {
const repoDetails = await this.getRepoDetails(url);
const commitSha = repoDetails.branch.commit.sha!;
if (options?.etag && options.etag === commitSha) {
throw new NotModifiedError();
}
const { filepath } = parseGitUrl(url);
const { headers } = await this.deps.credentialsProvider.getCredentials({
url,
});
const files = await this.doSearch(
url,
repoDetails.repo.trees_url,
repoDetails.repo.archive_url,
commitSha,
filepath,
{ headers },
);
const { filepath } = parseGitUrl(url);
return await this.deps.treeResponseFactory.fromTarArchive({
// TODO(Rugvip): Underlying implementation of fetch will be node-fetch, we probably want
// to stick to using that in exclusively backend code.
stream: (archive.body as unknown) as Readable,
subpath: filepath,
etag: commitSha,
filter: options?.filter,
});
return { files, etag: commitSha };
}
toString() {
@@ -134,11 +159,92 @@ export class GithubUrlReader implements UrlReader {
return `github{host=${host},authed=${Boolean(token)}}`;
}
private async doReadTree(
archiveUrl: string,
sha: string,
subpath: string,
init: RequestInit,
options?: ReadTreeOptions,
): Promise<ReadTreeResponse> {
// archive_url looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}"
const archive = await this.fetchResponse(
archiveUrl
.replace('{archive_format}', 'tarball')
.replace('{/ref}', `/${sha}`),
init,
);
return await this.deps.treeResponseFactory.fromTarArchive({
// TODO(Rugvip): Underlying implementation of fetch will be node-fetch, we probably want
// to stick to using that in exclusively backend code.
stream: (archive.body as unknown) as Readable,
subpath,
etag: sha,
filter: options?.filter,
});
}
private async doSearch(
url: string,
treesUrl: string,
archiveUrl: string,
sha: string,
query: string,
init: RequestInit,
): Promise<SearchResponseFile[]> {
function pathToUrl(path: string): string {
// TODO(freben): Use the integration package facility for this instead
// pathname starts as /backstage/backstage/blob/master/<path>
const updated = new URL(url);
const base = updated.pathname.split('/').slice(1, 5).join('/');
updated.pathname = `${base}/${path}`;
return updated.toString();
}
const matcher = new Minimatch(query.replace(/^\/+/, ''));
// trees_url looks like "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}"
const recursiveTree: GhTreeResponse = await this.fetchJson(
treesUrl.replace('{/sha}', `/${sha}?recursive=true`),
init,
);
// The simple case is that we got the entire tree in a single operation.
if (!recursiveTree.truncated) {
const matching = recursiveTree.tree.filter(
item =>
item.type === 'blob' &&
item.path &&
item.url &&
matcher.match(item.path),
);
return matching.map(item => ({
url: pathToUrl(item.path!),
content: async () => {
const blob: GhBlobResponse = await this.fetchJson(item.url!, init);
return Buffer.from(blob.content, 'base64');
},
}));
}
// For larger repos, we leverage readTree and filter through that instead
const tree = await this.doReadTree(archiveUrl, sha, '', init, {
filter: path => matcher.match(path),
});
const files = await tree.files();
return files.map(file => ({
url: pathToUrl(file.path),
content: file.content,
}));
}
private async getRepoDetails(
url: string,
): Promise<{
repo: RestEndpointMethodTypes['repos']['get']['response']['data'];
branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data'];
repo: GhRepoResponse;
branch: GhBranchResponse;
}> {
const parsed = parseGitUrl(url);
const { ref, full_name } = parsed;
@@ -151,13 +257,13 @@ export class GithubUrlReader implements UrlReader {
url,
});
const repo: RestEndpointMethodTypes['repos']['get']['response']['data'] = await this.fetchJson(
const repo: GhRepoResponse = await this.fetchJson(
`${this.config.apiBaseUrl}/repos/${full_name}`,
{ headers },
);
// branches_url looks like "https://api.github.com/repos/owner/repo/branches{/branch}"
const branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data'] = await this.fetchJson(
const branch: GhBranchResponse = await this.fetchJson(
repo.branches_url.replace('{/branch}', `/${ref || repo.default_branch}`),
{ headers },
);
@@ -36,6 +36,7 @@ const gitlabProcessor = new GitlabUrlReader(
{
host: 'gitlab.com',
apiBaseUrl: 'https://gitlab.com/api/v4',
baseUrl: 'https://gitlab.com',
},
{ treeResponseFactory },
);
@@ -44,6 +45,7 @@ const hostedGitlabProcessor = new GitlabUrlReader(
{
host: 'gitlab.mycompany.com',
apiBaseUrl: 'https://gitlab.mycompany.com/api/v4',
baseUrl: 'https://gitlab.mycompany.com',
},
{ treeResponseFactory },
);
@@ -379,17 +381,5 @@ describe('GitlabUrlReader', () => {
};
await expect(fnGithub).rejects.toThrow(NotFoundError);
});
it('should throw error when apiBaseUrl is missing', () => {
expect(() => {
/* eslint-disable no-new */
new GitlabUrlReader(
{
host: 'gitlab.mycompany.com',
},
{ treeResponseFactory },
);
}).toThrowError('must configure an explicit apiBaseUrl');
});
});
});
@@ -21,16 +21,17 @@ import {
readGitLabIntegrationConfigs,
} from '@backstage/integration';
import fetch from 'cross-fetch';
import parseGitUrl from 'git-url-parse';
import { Readable } from 'stream';
import { NotFoundError, NotModifiedError } from '../errors';
import { ReadTreeResponseFactory } from './tree';
import {
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,
SearchResponse,
UrlReader,
} from './types';
import parseGitUrl from 'git-url-parse';
import { Readable } from 'stream';
export class GitlabUrlReader implements UrlReader {
private readonly treeResponseFactory: ReadTreeResponseFactory;
@@ -51,12 +52,6 @@ export class GitlabUrlReader implements UrlReader {
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.treeResponseFactory = deps.treeResponseFactory;
if (!config.apiBaseUrl) {
throw new Error(
`GitLab integration for '${config.host}' must configure an explicit apiBaseUrl`,
);
}
}
async read(url: string): Promise<Buffer> {
@@ -154,6 +149,10 @@ export class GitlabUrlReader implements UrlReader {
});
}
async search(): Promise<SearchResponse> {
throw new Error('GitlabUrlReader does not implement search');
}
toString() {
const { host, token } = this.config;
return `gitlab{host=${host},authed=${Boolean(token)}}`;
@@ -18,6 +18,8 @@ import { NotAllowedError } from '../errors';
import {
ReadTreeOptions,
ReadTreeResponse,
SearchOptions,
SearchResponse,
UrlReader,
UrlReaderPredicateTuple,
} from './types';
@@ -60,6 +62,18 @@ export class UrlReaderPredicateMux implements UrlReader {
throw new NotAllowedError(`Reading from '${url}' is not allowed`);
}
async search(url: string, options?: SearchOptions): Promise<SearchResponse> {
const parsed = new URL(url);
for (const { predicate, reader } of this.readers) {
if (predicate(parsed)) {
return await reader.search(url, options);
}
}
throw new NotAllowedError(`Reading from '${url}' is not allowed`);
}
toString() {
return `predicateMux{readers=${this.readers.map(t => t.reader).join(',')}`;
}
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
export type { UrlReader, ReadTreeResponse } from './types';
export type { UrlReader, ReadTreeResponse, SearchResponse } from './types';
export { UrlReaders } from './UrlReaders';
export { AzureUrlReader } from './AzureUrlReader';
export { BitbucketUrlReader } from './BitbucketUrlReader';
@@ -24,6 +24,7 @@ import { ReadTreeResponseFactory } from './tree';
export type UrlReader = {
read(url: string): Promise<Buffer>;
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
};
export type UrlReaderPredicateTuple = {
@@ -103,3 +104,51 @@ export type ReadTreeResponseFile = {
path: string;
content(): Promise<Buffer>;
};
/**
* An options object for search operations.
*/
export type SearchOptions = {
/**
* An etag can be provided to check whether the search response has changed from a previous execution.
*
* In the search() response, an etag is returned along with the files. The etag is a unique identifer
* of the current tree, usually the commit SHA or etag from the target.
*
* When an etag is given in SearchOptions, search will first compare the etag against the etag
* on the target branch. If they match, search will throw a NotModifiedError indicating that the search
* response will not differ from the previous response which included this particular etag. If they mismatch,
* search will return the rest of SearchResponse along with a new etag.
*/
etag?: string;
};
/**
* The output of a search operation.
*/
export type SearchResponse = {
/**
* The files that matched the search query.
*/
files: SearchResponseFile[];
/**
* A unique identifer of the current remote tree, usually the commit SHA or etag from the target.
*/
etag: string;
};
/**
* Represents a single file in a search response.
*/
export type SearchResponseFile = {
/**
* The full URL to the file.
*/
url: string;
/**
* The binary contents of the file.
*/
content(): Promise<Buffer>;
};
+29
View File
@@ -1,5 +1,34 @@
# example-backend
## 0.2.15
### Patch Changes
- Updated dependencies [1deb31141]
- Updated dependencies [6ed2b47d6]
- Updated dependencies [77ad0003a]
- Updated dependencies [d2441aee3]
- Updated dependencies [727f0deec]
- Updated dependencies [fb53eb7cb]
- Updated dependencies [07bafa248]
- Updated dependencies [ffffea8e6]
- Updated dependencies [f3fbfb452]
- Updated dependencies [615103a63]
- Updated dependencies [84364b35c]
- Updated dependencies [82b2c11b6]
- Updated dependencies [965e200c6]
- Updated dependencies [5a5163519]
- Updated dependencies [82b2c11b6]
- Updated dependencies [08142b256]
- Updated dependencies [08142b256]
- @backstage/plugin-auth-backend@0.3.0
- @backstage/plugin-scaffolder-backend@0.7.0
- @backstage/plugin-catalog-backend@0.6.1
- @backstage/plugin-app-backend@0.3.7
- example-app@0.2.15
- @backstage/backend-common@0.5.3
- @backstage/plugin-techdocs-backend@0.6.0
## 0.2.14
### Patch Changes
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.14",
"version": "0.2.15",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -27,24 +27,24 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.5.2",
"@backstage/backend-common": "^0.5.3",
"@backstage/catalog-model": "^0.7.1",
"@backstage/config": "^0.1.2",
"@backstage/plugin-app-backend": "^0.3.6",
"@backstage/plugin-auth-backend": "^0.2.12",
"@backstage/plugin-catalog-backend": "^0.6.0",
"@backstage/plugin-app-backend": "^0.3.7",
"@backstage/plugin-auth-backend": "^0.3.0",
"@backstage/plugin-catalog-backend": "^0.6.1",
"@backstage/plugin-graphql-backend": "^0.1.5",
"@backstage/plugin-kubernetes-backend": "^0.2.6",
"@backstage/plugin-kafka-backend": "^0.2.0",
"@backstage/plugin-proxy-backend": "^0.2.4",
"@backstage/plugin-rollbar-backend": "^0.1.7",
"@backstage/plugin-scaffolder-backend": "^0.6.0",
"@backstage/plugin-techdocs-backend": "^0.5.5",
"@backstage/plugin-scaffolder-backend": "^0.7.0",
"@backstage/plugin-techdocs-backend": "^0.6.0",
"@gitbeaker/node": "^28.0.2",
"@octokit/rest": "^18.0.12",
"azure-devops-node-api": "^10.1.1",
"dockerode": "^3.2.1",
"example-app": "^0.2.14",
"example-app": "^0.2.15",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"knex": "^0.21.6",
+7
View File
@@ -1,5 +1,12 @@
# @backstage/catalog-client
## 0.3.6
### Patch Changes
- 6ed2b47d6: Include Backstage identity token in requests to backend plugins.
- 72b96e880: Add the `presence` argument to the `CatalogApi` to be able to register optional locations.
## 0.3.5
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/catalog-client",
"version": "0.3.5",
"version": "0.3.6",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,6 +21,7 @@ import { CatalogClient } from './CatalogClient';
import { CatalogListResponse, DiscoveryApi } from './types';
const server = setupServer();
const token = 'fake-token';
const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base';
const discoveryApi: DiscoveryApi = {
async getBaseUrl(_pluginId) {
@@ -71,7 +72,7 @@ describe('CatalogClient', () => {
});
it('should entities from correct endpoint', async () => {
const response = await client.getEntities();
const response = await client.getEntities({}, { token });
expect(response).toEqual(defaultResponse);
});
@@ -85,13 +86,16 @@ describe('CatalogClient', () => {
}),
);
const response = await client.getEntities({
filter: {
a: '1',
b: ['2', '3'],
ö: '=',
const response = await client.getEntities(
{
filter: {
a: '1',
b: ['2', '3'],
ö: '=',
},
},
});
{ token },
);
expect(response.items).toEqual([]);
});
@@ -106,11 +110,61 @@ describe('CatalogClient', () => {
}),
);
const response = await client.getEntities({
fields: ['a.b', 'ö'],
});
const response = await client.getEntities(
{
fields: ['a.b', 'ö'],
},
{ token },
);
expect(response.items).toEqual([]);
});
});
describe('getLocationById', () => {
const defaultResponse = {
data: {
id: '42',
},
};
beforeEach(() => {
server.use(
rest.get(`${mockBaseUrl}/locations/42`, (_, res, ctx) => {
return res(ctx.json(defaultResponse));
}),
);
});
it('should locations from correct endpoint', async () => {
const response = await client.getLocationById('42', { token });
expect(response).toEqual(defaultResponse);
});
it('forwards authorization token', async () => {
expect.assertions(1);
server.use(
rest.get(`${mockBaseUrl}/locations/42`, (req, res, ctx) => {
expect(req.headers.get('authorization')).toBe(`Bearer ${token}`);
return res(ctx.json(defaultResponse));
}),
);
await client.getLocationById('42', { token });
});
it('skips authorization header if token is omitted', async () => {
expect.assertions(1);
server.use(
rest.get(`${mockBaseUrl}/locations/42`, (req, res, ctx) => {
expect(req.headers.get('authorization')).toBeNull();
return res(ctx.json(defaultResponse));
}),
);
await client.getLocationById('42');
});
});
});
+58 -18
View File
@@ -24,6 +24,7 @@ import fetch from 'cross-fetch';
import {
AddLocationRequest,
AddLocationResponse,
CatalogRequestOptions,
CatalogApi,
CatalogEntitiesRequest,
CatalogListResponse,
@@ -37,12 +38,16 @@ export class CatalogClient implements CatalogApi {
this.discoveryApi = options.discoveryApi;
}
async getLocationById(id: String): Promise<Location | undefined> {
return await this.getOptional(`/locations/${id}`);
async getLocationById(
id: String,
options?: CatalogRequestOptions,
): Promise<Location | undefined> {
return await this.getOptional(`/locations/${id}`, options);
}
async getEntities(
request?: CatalogEntitiesRequest,
options?: CatalogRequestOptions,
): Promise<CatalogListResponse<Entity>> {
const { filter = {}, fields = [] } = request ?? {};
const params: string[] = [];
@@ -62,20 +67,28 @@ export class CatalogClient implements CatalogApi {
}
const query = params.length ? `?${params.join('&')}` : '';
const entities: Entity[] = await this.getRequired(`/entities${query}`);
const entities: Entity[] = await this.getRequired(
`/entities${query}`,
options,
);
return { items: entities };
}
async getEntityByName(compoundName: EntityName): Promise<Entity | undefined> {
async getEntityByName(
compoundName: EntityName,
options?: CatalogRequestOptions,
): Promise<Entity | undefined> {
const { kind, namespace = 'default', name } = compoundName;
return this.getOptional(`/entities/by-name/${kind}/${namespace}/${name}`);
return this.getOptional(
`/entities/by-name/${kind}/${namespace}/${name}`,
options,
);
}
async addLocation({
type = 'url',
target,
dryRun,
}: AddLocationRequest): Promise<AddLocationResponse> {
async addLocation(
{ type = 'url', target, dryRun, presence }: AddLocationRequest,
options?: CatalogRequestOptions,
): Promise<AddLocationResponse> {
const response = await fetch(
`${await this.discoveryApi.getBaseUrl('catalog')}/locations${
dryRun ? '?dryRun=true' : ''
@@ -83,9 +96,10 @@ export class CatalogClient implements CatalogApi {
{
headers: {
'Content-Type': 'application/json',
...(options?.token && { Authorization: `Bearer ${options?.token}` }),
},
method: 'POST',
body: JSON.stringify({ type, target }),
body: JSON.stringify({ type, target, presence }),
},
);
@@ -110,18 +124,30 @@ export class CatalogClient implements CatalogApi {
};
}
async getLocationByEntity(entity: Entity): Promise<Location | undefined> {
async getLocationByEntity(
entity: Entity,
options?: CatalogRequestOptions,
): Promise<Location | undefined> {
const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];
const all: { data: Location }[] = await this.getRequired('/locations');
const all: { data: Location }[] = await this.getRequired(
'/locations',
options,
);
return all
.map(r => r.data)
.find(l => locationCompound === `${l.type}:${l.target}`);
}
async removeEntityByUid(uid: string): Promise<void> {
async removeEntityByUid(
uid: string,
options?: CatalogRequestOptions,
): Promise<void> {
const response = await fetch(
`${await this.discoveryApi.getBaseUrl('catalog')}/entities/by-uid/${uid}`,
{
headers: options?.token
? { Authorization: `Bearer ${options.token}` }
: {},
method: 'DELETE',
},
);
@@ -138,9 +164,16 @@ export class CatalogClient implements CatalogApi {
// Private methods
//
private async getRequired(path: string): Promise<any> {
private async getRequired(
path: string,
options?: CatalogRequestOptions,
): Promise<any> {
const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;
const response = await fetch(url);
const response = await fetch(url, {
headers: options?.token
? { Authorization: `Bearer ${options.token}` }
: {},
});
if (!response.ok) {
const payload = await response.text();
@@ -151,9 +184,16 @@ export class CatalogClient implements CatalogApi {
return await response.json();
}
private async getOptional(path: string): Promise<any | undefined> {
private async getOptional(
path: string,
options?: CatalogRequestOptions,
): Promise<any | undefined> {
const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;
const response = await fetch(url);
const response = await fetch(url, {
headers: options?.token
? { Authorization: `Bearer ${options.token}` }
: {},
});
if (!response.ok) {
if (response.status === 404) {
+7 -1
View File
@@ -15,4 +15,10 @@
*/
export { CatalogClient } from './CatalogClient';
export type { CatalogApi } from './types';
export type {
AddLocationRequest,
AddLocationResponse,
CatalogApi,
CatalogEntitiesRequest,
CatalogListResponse,
} from './types';
+26 -5
View File
@@ -25,21 +25,42 @@ export type CatalogListResponse<T> = {
items: T[];
};
export type CatalogRequestOptions = {
token?: string;
};
export interface CatalogApi {
getLocationById(id: String): Promise<Location | undefined>;
getEntityByName(name: EntityName): Promise<Entity | undefined>;
getLocationById(
id: String,
options?: CatalogRequestOptions,
): Promise<Location | undefined>;
getEntityByName(
name: EntityName,
options?: CatalogRequestOptions,
): Promise<Entity | undefined>;
getEntities(
request?: CatalogEntitiesRequest,
options?: CatalogRequestOptions,
): Promise<CatalogListResponse<Entity>>;
addLocation(location: AddLocationRequest): Promise<AddLocationResponse>;
getLocationByEntity(entity: Entity): Promise<Location | undefined>;
removeEntityByUid(uid: string): Promise<void>;
addLocation(
location: AddLocationRequest,
options?: CatalogRequestOptions,
): Promise<AddLocationResponse>;
getLocationByEntity(
entity: Entity,
options?: CatalogRequestOptions,
): Promise<Location | undefined>;
removeEntityByUid(
uid: string,
options?: CatalogRequestOptions,
): Promise<void>;
}
export type AddLocationRequest = {
type?: string;
target: string;
dryRun?: boolean;
presence?: 'optional' | 'required';
};
export type AddLocationResponse = {
@@ -7,11 +7,24 @@ metadata:
- java
- data
links:
- url: https://example.com/apm/artists-lookup
title: APM
- url: https://example.com/user
title: Examples Users
icon: user
- url: https://example.com/group
title: Example Group
icon: group
- url: https://example.com/cloud
title: Link with Cloud Icon
icon: cloud
- url: https://example.com/dashboard
title: Dashboard
icon: dashboard
- url: https://example.com/logs/artists-lookup
title: Logs
- url: https://example.com/help
title: Support
icon: help
- url: https://example.com/web
title: Website
icon: web
spec:
type: service
lifecycle: experimental
+2 -2
View File
@@ -43,7 +43,7 @@
"@spotify/eslint-config-react": "^9.0.0",
"@spotify/eslint-config-typescript": "^9.0.0",
"@sucrase/webpack-loader": "^2.0.0",
"@svgr/plugin-jsx": "5.4.x",
"@svgr/plugin-jsx": "5.5.x",
"@svgr/plugin-svgo": "5.4.x",
"@svgr/rollup": "5.5.x",
"@svgr/webpack": "5.4.x",
@@ -93,7 +93,7 @@
"rollup-plugin-esbuild": "2.6.x",
"rollup-plugin-peer-deps-external": "^2.2.2",
"rollup-plugin-postcss": "^3.1.1",
"rollup-plugin-typescript2": "^0.27.3",
"rollup-plugin-typescript2": "^0.29.0",
"rollup-pluginutils": "^2.8.2",
"semver": "^7.3.2",
"start-server-webpack-plugin": "^2.2.5",
+6
View File
@@ -1,5 +1,11 @@
# @backstage/core
## 0.6.1
### Patch Changes
- b51ee6ece: Fixed type inference of `createRouteRef`.
## 0.6.0
### Minor Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core",
"description": "Core API used by Backstage plugins and apps",
"version": "0.6.0",
"version": "0.6.1",
"private": false,
"publishConfig": {
"access": "public",
@@ -67,7 +67,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.6.0",
"@backstage/test-utils": "^0.1.6",
"@backstage/test-utils": "^0.1.7",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
@@ -15,8 +15,17 @@
*/
import React, { FunctionComponentFactory } from 'react';
import { Button } from './Button';
import { MemoryRouter, Route, useLocation } from 'react-router-dom';
import { MemoryRouter, useLocation } from 'react-router-dom';
import { createRouteRef } from '@backstage/core-api';
import {
Divider,
Link,
List,
ListItem,
ListItemText,
Typography,
Button as MaterialButton,
} from '@material-ui/core';
const Location = () => {
const location = useLocation();
@@ -28,14 +37,27 @@ export default {
component: Button,
decorators: [
(storyFn: FunctionComponentFactory<{}>) => (
<MemoryRouter>
<div>
<>
<Typography>
A collection of buttons that should be used in the Backstage
interface. These leverage the properties inherited from{' '}
<Link href="https://material-ui.com/components/buttons/">
Material-UI Button
</Link>
, but include an opinionated set that align to the Backstage design.
</Typography>
<Divider />
<MemoryRouter>
<div>
<Location />
<div>
<Location />
</div>
{storyFn()}
</div>
{storyFn()}
</div>
</MemoryRouter>
</MemoryRouter>
</>
),
],
};
@@ -46,36 +68,107 @@ export const Default = () => {
title: 'Hi there!',
});
// Design Permutations:
// color = default | primary | secondary
// variant = contained | outlined | text
return (
<>
<Button to={routeRef.path}>This button</Button>&nbsp;will utilise the
react-router MemoryRouter's navigation
<Route path={routeRef.path}>
<h1>{routeRef.title}</h1>
</Route>
</>
<List>
<ListItem>
<ListItemText>
<Typography variant="h6">Default Button:</Typography>
This is the default button design which should be used in most cases.
<br />
<pre>color="primary" variant="contained"</pre>
</ListItemText>
<Button to={routeRef.path} color="primary" variant="contained">
Register Component
</Button>
</ListItem>
<ListItem>
<ListItemText>
<Typography variant="h6">Secondary Button:</Typography>
Used for actions that cancel, skip, and in general perform negative
functions, etc.
<br />
<pre>color="secondary" variant="contained"</pre>
</ListItemText>
<Button to={routeRef.path} color="secondary" variant="contained">
Cancel
</Button>
</ListItem>
<ListItem>
<ListItemText>
<Typography variant="h6">Tertiary Button:</Typography>
Used commonly in a ButtonGroup and when the button function itself is
not a primary function on a page.
<br />
<pre>color="default" variant="outlined"</pre>
</ListItemText>
<Button to={routeRef.path} color="default" variant="outlined">
View Details
</Button>
</ListItem>
</List>
);
};
export const PassProps = () => {
export const ButtonLinks = () => {
const routeRef = createRouteRef({
path: '/hello',
title: 'Hi there!',
});
const handleClick = () => {
return 'Your click worked!';
};
return (
<>
<Button to={routeRef.path} color="secondary" variant="outlined">
This link
</Button>
&nbsp;has props for both material-ui's component as well as for
react-router-dom's
<Route path={routeRef.path}>
<h1>{routeRef.title}</h1>
</Route>
<List>
{
// TODO: Refactor to use new routing mechanisms
}
<ListItem>
<Button to={routeRef.path} color="default" variant="outlined">
Route Ref
</Button>
&nbsp; has props for both Material-UI's component as well as for
react-router-dom's Route object.
</ListItem>
<ListItem>
<Button to="/staticpath" color="default" variant="outlined">
Static Path
</Button>
&nbsp; links to a statically defined route. In general, this should be
avoided.
</ListItem>
<ListItem>
<MaterialButton
href="https://backstage.io"
color="default"
variant="outlined"
>
View URL
</MaterialButton>
&nbsp; links to a defined URL using Material-UI's Button.
</ListItem>
<ListItem>
<MaterialButton
onClick={handleClick}
color="default"
variant="outlined"
>
Trigger Event
</MaterialButton>
&nbsp; triggers an onClick event using Material-UI's Button.
</ListItem>
</List>
</>
);
};
PassProps.story = {
name: `Accepts material-ui Button's and react-router-dom Link's props`,
};
@@ -215,7 +215,6 @@ export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
{...childProps}
activeClassName={classes.selected}
to={props.to}
end
ref={ref}
>
{content}
+96
View File
@@ -1,5 +1,101 @@
# @backstage/create-app
## 0.3.9
### Patch Changes
- 615103a63: Pass on plugin database management instance that is now required by the scaffolder plugin.
To apply this change to an existing application, add the following to `src/plugins/scaffolder.ts`:
```diff
export default async function createPlugin({
logger,
config,
+ database,
}: PluginEnvironment) {
// ...omitted...
return await createRouter({
preparers,
templaters,
publishers,
logger,
config,
dockerClient,
entityClient,
+ database,
});
}
```
- 30e200d12: `@backstage/plugin-catalog-import` has been refactored, so the `App.tsx` of the backstage apps need to be updated:
```diff
// packages/app/src/App.tsx
<Route
path="/catalog-import"
- element={<CatalogImportPage catalogRouteRef={catalogRouteRef} />}
+ element={<CatalogImportPage />}
/>
```
- f4b576d0e: TechDocs: Add comments about migrating away from basic setup in app-config.yaml
- Updated dependencies [753bb4c40]
- Updated dependencies [1deb31141]
- Updated dependencies [6ed2b47d6]
- Updated dependencies [77ad0003a]
- Updated dependencies [6b26c9f41]
- Updated dependencies [b3f0c3811]
- Updated dependencies [d2441aee3]
- Updated dependencies [727f0deec]
- Updated dependencies [fb53eb7cb]
- Updated dependencies [07bafa248]
- Updated dependencies [ca559171b]
- Updated dependencies [ffffea8e6]
- Updated dependencies [f5e564cd6]
- Updated dependencies [f3fbfb452]
- Updated dependencies [615103a63]
- Updated dependencies [68dd79d83]
- Updated dependencies [84364b35c]
- Updated dependencies [41af18227]
- Updated dependencies [82b2c11b6]
- Updated dependencies [1df75733e]
- Updated dependencies [965e200c6]
- Updated dependencies [b51ee6ece]
- Updated dependencies [e5da858d7]
- Updated dependencies [9230d07e7]
- Updated dependencies [f5f45744e]
- Updated dependencies [0fe8ff5be]
- Updated dependencies [5a5163519]
- Updated dependencies [82b2c11b6]
- Updated dependencies [8f3443427]
- Updated dependencies [08142b256]
- Updated dependencies [08142b256]
- Updated dependencies [b51ee6ece]
- Updated dependencies [804502a5c]
- @backstage/plugin-catalog-import@0.4.0
- @backstage/plugin-auth-backend@0.3.0
- @backstage/plugin-catalog@0.3.1
- @backstage/plugin-scaffolder@0.5.0
- @backstage/plugin-scaffolder-backend@0.7.0
- @backstage/plugin-catalog-backend@0.6.1
- @backstage/plugin-circleci@0.2.8
- @backstage/plugin-search@0.3.0
- @backstage/plugin-app-backend@0.3.7
- @backstage/backend-common@0.5.3
- @backstage/plugin-api-docs@0.4.5
- @backstage/plugin-lighthouse@0.2.10
- @backstage/plugin-techdocs@0.5.6
- @backstage/test-utils@0.1.7
- @backstage/plugin-github-actions@0.3.2
- @backstage/plugin-explore@0.2.5
- @backstage/plugin-techdocs-backend@0.6.0
- @backstage/core@0.6.1
- @backstage/plugin-tech-radar@0.3.5
## 0.3.8
### Patch Changes

Some files were not shown because too many files have changed in this diff Show More