diff --git a/.changeset/brave-pugs-fold.md b/.changeset/brave-pugs-fold.md new file mode 100644 index 0000000000..f79867a719 --- /dev/null +++ b/.changeset/brave-pugs-fold.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': patch +--- + +Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration. diff --git a/.changeset/clean-wolves-jog.md b/.changeset/clean-wolves-jog.md new file mode 100644 index 0000000000..70ab23715f --- /dev/null +++ b/.changeset/clean-wolves-jog.md @@ -0,0 +1,5 @@ +--- +'@backstage/config': patch +--- + +The `ConfigReader#get` method now always returns a deep clone of the configuration data. diff --git a/.changeset/cold-steaks-flash.md b/.changeset/cold-steaks-flash.md new file mode 100644 index 0000000000..74cdcbdec2 --- /dev/null +++ b/.changeset/cold-steaks-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +fix: Register plugin to prioritise Component kind for entityRef diff --git a/.changeset/dry-boats-tap.md b/.changeset/dry-boats-tap.md new file mode 100644 index 0000000000..c69c4360b5 --- /dev/null +++ b/.changeset/dry-boats-tap.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-todo-backend': patch +--- + +Properly exported all referenced types diff --git a/.changeset/eight-rats-raise.md b/.changeset/eight-rats-raise.md new file mode 100644 index 0000000000..7bc2a07f04 --- /dev/null +++ b/.changeset/eight-rats-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Add catalog permission rules. diff --git a/.changeset/fair-bikes-scream.md b/.changeset/fair-bikes-scream.md new file mode 100644 index 0000000000..decdfd3828 --- /dev/null +++ b/.changeset/fair-bikes-scream.md @@ -0,0 +1,28 @@ +--- +'@backstage/cli': minor +--- + +ESLint upgraded to version 8 and all it's plugins updated to newest version. + +If you use any custom plugins for ESLint please check compatibility. + +```diff +- "@typescript-eslint/eslint-plugin": "^v4.33.0", +- "@typescript-eslint/parser": "^v4.28.3", ++ "@typescript-eslint/eslint-plugin": "^5.9.0", ++ "@typescript-eslint/parser": "^5.9.0", +- "eslint": "^7.30.0", ++ "eslint": "^8.6.0", +- "eslint-plugin-import": "^2.20.2", +- "eslint-plugin-jest": "^24.1.0", +- "eslint-plugin-jsx-a11y": "^6.2.1", ++ "eslint-plugin-import": "^2.25.4", ++ "eslint-plugin-jest": "^25.3.4", ++ "eslint-plugin-jsx-a11y": "^6.5.1", +- "eslint-plugin-react": "^7.12.4", +- "eslint-plugin-react-hooks": "^4.0.0", ++ "eslint-plugin-react": "^7.28.0", ++ "eslint-plugin-react-hooks": "^4.3.0", +``` + +Please consult changelogs from packages if you find any problems. diff --git a/.changeset/fluffy-toys-tease.md b/.changeset/fluffy-toys-tease.md deleted file mode 100644 index f20eaebb2c..0000000000 --- a/.changeset/fluffy-toys-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': minor ---- - -fixes api auth in tech-insights plugin diff --git a/.changeset/four-ghosts-sniff.md b/.changeset/four-ghosts-sniff.md new file mode 100644 index 0000000000..9da0ab15ed --- /dev/null +++ b/.changeset/four-ghosts-sniff.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': minor +--- + +Removed the deprecated `OldIconComponent` type. diff --git a/.changeset/funny-llamas-yell.md b/.changeset/funny-llamas-yell.md new file mode 100644 index 0000000000..890caaa221 --- /dev/null +++ b/.changeset/funny-llamas-yell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-graphql': patch +--- + +Bump graphql versions diff --git a/.changeset/fuzzy-llamas-collect.md b/.changeset/fuzzy-llamas-collect.md new file mode 100644 index 0000000000..17ee925e56 --- /dev/null +++ b/.changeset/fuzzy-llamas-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': patch +--- + +Make sure to avoid accidental data sharing / mutation of `set` values diff --git a/.changeset/healthy-toes-laugh.md b/.changeset/healthy-toes-laugh.md new file mode 100644 index 0000000000..e0db38e5e3 --- /dev/null +++ b/.changeset/healthy-toes-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +Add helpers for creating PermissionRules with inferred types diff --git a/.changeset/lazy-gorillas-tell.md b/.changeset/lazy-gorillas-tell.md new file mode 100644 index 0000000000..672d8c221b --- /dev/null +++ b/.changeset/lazy-gorillas-tell.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-plugin-api': minor +--- + +Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`. + +The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`. diff --git a/.changeset/long-otters-promise.md b/.changeset/long-otters-promise.md new file mode 100644 index 0000000000..eecb97e8ac --- /dev/null +++ b/.changeset/long-otters-promise.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-catalog-backend-module-msgraph': patch +--- + +Clean up API report diff --git a/.changeset/lucky-bats-reflect.md b/.changeset/lucky-bats-reflect.md deleted file mode 100644 index ad3171382e..0000000000 --- a/.changeset/lucky-bats-reflect.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend': patch ---- - -Uptake changes to the GitHub Credentials Provider interface. diff --git a/.changeset/nervous-starfishes-report.md b/.changeset/nervous-starfishes-report.md new file mode 100644 index 0000000000..2ac4179a2c --- /dev/null +++ b/.changeset/nervous-starfishes-report.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': patch +--- + +Adds two new home components - CompanyLogo and Toolkit. diff --git a/.changeset/olive-points-flash.md b/.changeset/olive-points-flash.md new file mode 100644 index 0000000000..64b23419de --- /dev/null +++ b/.changeset/olive-points-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switch Webpack minification to use `esbuild` instead of `terser`. diff --git a/.changeset/pink-suns-walk.md b/.changeset/pink-suns-walk.md new file mode 100644 index 0000000000..1857b90811 --- /dev/null +++ b/.changeset/pink-suns-walk.md @@ -0,0 +1,25 @@ +--- +'@backstage/backend-common': patch +'@backstage/core-components': patch +'@backstage/create-app': patch +'@backstage/integration': patch +'@backstage/techdocs-common': patch +'@backstage/plugin-apache-airflow': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-code-coverage-backend': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-jenkins': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-search-backend-node': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-techdocs-backend': patch +--- + +Cleaned up API exports diff --git a/.changeset/plenty-eyes-brush.md b/.changeset/plenty-eyes-brush.md new file mode 100644 index 0000000000..354c216c3c --- /dev/null +++ b/.changeset/plenty-eyes-brush.md @@ -0,0 +1,60 @@ +--- +'@backstage/create-app': patch +--- + +Add permissions to create-app's PluginEnvironment + +`CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`: + +```diff + // packages/backend/src/index.ts + ++ import { ServerPermissionClient } from '@backstage/plugin-permission-node'; + + function makeCreateEnv(config: Config) { + ... ++ const permissions = ServerPerimssionClient.fromConfig(config, { ++ discovery, ++ tokenManager, ++ }); + + root.info(`Created UrlReader ${reader}`); + + return (plugin: string): PluginEnvironment => { + ... + return { + logger, + cache, + database, + config, + reader, + discovery, + tokenManager, + scheduler, ++ permissions, + }; + } + } +``` + +And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`: + +```diff + // packages/backend/src/types.ts + ++ import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; + + export type PluginEnvironment = { + ... ++ permissions: PermissionAuthorizer; + }; +``` + +[`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies: + +```diff + // packages/backend/package.json + ++ "@backstage/plugin-permission-common": "...", ++ "@backstage/plugin-permission-node": "...", +``` diff --git a/.changeset/popular-cycles-work.md b/.changeset/popular-cycles-work.md new file mode 100644 index 0000000000..939f59de94 --- /dev/null +++ b/.changeset/popular-cycles-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +bump `logform` to use fixed version of `color` dependency diff --git a/.changeset/quiet-carpets-shake.md b/.changeset/quiet-carpets-shake.md new file mode 100644 index 0000000000..a0744651e3 --- /dev/null +++ b/.changeset/quiet-carpets-shake.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-splunk-on-call': patch +--- + +Clean up emptystate.svg image, removing wrong white artifact from the background diff --git a/.changeset/rotten-files-wink.md b/.changeset/rotten-files-wink.md new file mode 100644 index 0000000000..65bd92bcc5 --- /dev/null +++ b/.changeset/rotten-files-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`. diff --git a/.changeset/rotten-olives-shop.md b/.changeset/rotten-olives-shop.md new file mode 100644 index 0000000000..b7fb51ad06 --- /dev/null +++ b/.changeset/rotten-olives-shop.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well. diff --git a/.changeset/shaggy-emus-look.md b/.changeset/shaggy-emus-look.md new file mode 100644 index 0000000000..df8a1fe6fe --- /dev/null +++ b/.changeset/shaggy-emus-look.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-app-api': patch +--- + +Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored. + +Deprecated the `SamlSession` and `GithubSession` types. diff --git a/.changeset/short-schools-heal.md b/.changeset/short-schools-heal.md deleted file mode 100644 index 3976ea3a0c..0000000000 --- a/.changeset/short-schools-heal.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/integration': minor ---- - -Create an interface for the GitHub credentials provider in order to support providing implementations. - -We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`. - -`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials. - -In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers. - -If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`. diff --git a/.changeset/short-shoes-fail.md b/.changeset/short-shoes-fail.md new file mode 100644 index 0000000000..0b45d67a32 --- /dev/null +++ b/.changeset/short-shoes-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Removed `@backstage/test-utils` dependency. diff --git a/.changeset/silver-falcons-nail.md b/.changeset/silver-falcons-nail.md new file mode 100644 index 0000000000..970bbd7fee --- /dev/null +++ b/.changeset/silver-falcons-nail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Add apply-conditions endpoint for evaluating conditional permissions in catalog backend. diff --git a/.changeset/silver-knives-change.md b/.changeset/silver-knives-change.md new file mode 100644 index 0000000000..a2bbaf1e0b --- /dev/null +++ b/.changeset/silver-knives-change.md @@ -0,0 +1,6 @@ +--- +'@backstage/cli': patch +'@backstage/backend-common': patch +--- + +Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups. diff --git a/.changeset/silver-mice-bake.md b/.changeset/silver-mice-bake.md new file mode 100644 index 0000000000..6cba2fdb0a --- /dev/null +++ b/.changeset/silver-mice-bake.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': minor +--- + +Removed previously deprecated `ApiRegistry` export. diff --git a/.changeset/techdocs-light-onions-cover.md b/.changeset/techdocs-light-onions-cover.md new file mode 100644 index 0000000000..55c0873575 --- /dev/null +++ b/.changeset/techdocs-light-onions-cover.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes diff --git a/.changeset/tender-cars-look.md b/.changeset/tender-cars-look.md new file mode 100644 index 0000000000..f20ba447d4 --- /dev/null +++ b/.changeset/tender-cars-look.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Bump `testcontainers` dependency to version `8.1.2` diff --git a/.changeset/thin-buckets-juggle.md b/.changeset/thin-buckets-juggle.md new file mode 100644 index 0000000000..a95f8a86ad --- /dev/null +++ b/.changeset/thin-buckets-juggle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-airbrake': minor +--- + +A plugin for Airbrake (https://airbrake.io/) has been created diff --git a/.changeset/three-sheep-sparkle.md b/.changeset/three-sheep-sparkle.md new file mode 100644 index 0000000000..db6d8148ce --- /dev/null +++ b/.changeset/three-sheep-sparkle.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`. + +The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details. diff --git a/.changeset/twelve-bears-fail.md b/.changeset/twelve-bears-fail.md new file mode 100644 index 0000000000..6112f5a980 --- /dev/null +++ b/.changeset/twelve-bears-fail.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-app-api': patch +'@backstage/core-plugin-api': patch +--- + +Removed direct and transitive MUI dependencies. diff --git a/.changeset/twelve-panthers-move.md b/.changeset/twelve-panthers-move.md new file mode 100644 index 0000000000..f52050a488 --- /dev/null +++ b/.changeset/twelve-panthers-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Clean up API reports diff --git a/.changeset/violet-dingos-relate.md b/.changeset/violet-dingos-relate.md new file mode 100644 index 0000000000..c8b0c03e2c --- /dev/null +++ b/.changeset/violet-dingos-relate.md @@ -0,0 +1,7 @@ +--- +'@backstage/errors': minor +--- + +Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`. + +Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`. diff --git a/.changeset/warm-crews-flash.md b/.changeset/warm-crews-flash.md new file mode 100644 index 0000000000..b21a3ada02 --- /dev/null +++ b/.changeset/warm-crews-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Exclude the AWS session token from credential validation, because it's not necessary in this context. diff --git a/.changeset/warm-moles-battle.md b/.changeset/warm-moles-battle.md new file mode 100644 index 0000000000..3d203ea1d3 --- /dev/null +++ b/.changeset/warm-moles-battle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights': patch +--- + +fix React warning because of missing `key` prop diff --git a/.eslintrc.js b/.eslintrc.js index ec7b4f9130..47a47daee6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,12 +25,6 @@ module.exports = { { // eslint-disable-next-line no-restricted-syntax templateFile: path.resolve(__dirname, './scripts/copyright-header.txt'), - templateVars: { - NAME: 'The Backstage Authors', - }, - varRegexps: { - NAME: /(The Backstage Authors)|(Spotify AB)/, - }, onNonMatchingHeader: 'replace', }, ], diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9cc5a2378e..a587419d50 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -43,3 +43,4 @@ /.changeset/techdocs-* @backstage/techdocs-core /cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-core /plugins/apache-airflow @backstage/reviewers @cmpadden +/plugins/newrelic-dashboard @backstage/reviewers @mufaddal7 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 59847fd65f..65a4b1a438 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ updates: schedule: interval: daily time: '04:00' - open-pull-requests-limit: 5 + open-pull-requests-limit: 10 labels: - dependencies - package-ecosystem: npm @@ -13,6 +13,6 @@ updates: schedule: interval: daily time: '04:00' - open-pull-requests-limit: 2 + open-pull-requests-limit: 5 labels: - dependencies diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 8199855c9e..d3ea8c1c27 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -1,5 +1,6 @@ abc accessors +Airbrake Anddddd Apdex api diff --git a/.github/workflows/chromatic-storybook-test.yml b/.github/workflows/chromatic-storybook-test.yml index 4c64db309d..355ad65bee 100644 --- a/.github/workflows/chromatic-storybook-test.yml +++ b/.github/workflows/chromatic-storybook-test.yml @@ -4,6 +4,14 @@ on: paths: - '.github/workflows/chromatic-storybook-test.yml' - 'packages/storybook/**' + - 'packages/config/src/**' + - 'packages/theme/src/**' + - 'packages/types/src/**' + - 'packages/errors/src/**' + - 'packages/version-bridge/src/**' + - 'packages/test-utils/src/**' + - 'packages/core-app-api/src/**' + - 'packages/core-plugin-api/src/**' - 'packages/core-components/src/**' - '**/*.stories.tsx' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7222edef08..109f90eff6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,6 +124,9 @@ jobs: - name: check api reports and generate API reference run: yarn build:api-reports:only --ci --docs + - name: verify changesets + run: node scripts/verify-changesets.js + - name: verify doc links run: node scripts/verify-links.js diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5cbf4e32ef..f0bfe17326 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: for your contributions. days-before-issue-stale: 60 days-before-issue-close: 7 - exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc' + exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc,will-fix' stale-issue-label: stale stale-pr-message: > This PR has been automatically marked as stale because it has not had @@ -25,6 +25,6 @@ jobs: If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution! days-before-pr-stale: 7 days-before-pr-close: 5 - exempt-pr-labels: reviewer-approved,awaiting-review + exempt-pr-labels: reviewer-approved,awaiting-review,will-fix stale-pr-label: stale operations-per-run: 100 diff --git a/.gitignore b/.gitignore index 8c37280023..60d0d6da3b 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,6 @@ site # e2e tests cypress/cypress/* + +# Possible leftover from build:api-reports +tsconfig.tmp.json diff --git a/ADOPTERS.md b/ADOPTERS.md index 18337c414c..b35f6a3d77 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -77,3 +77,6 @@ | [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon), [Gauthier Roebroeck](https://github.com/gauthier-roebroeck-mox) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong πŸ₯°πŸš€ | | [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. πŸš— | | [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. | +| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding | +| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. | +| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [RafaΕ‚ Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time | diff --git a/README.md b/README.md index 3e91cfe7c3..1078631926 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ # [Backstage](https://backstage.io) -> πŸŽ„ The maintainers will be taking a break over the holidays from week beginning 20th Dec. The Repository and Discord may be quieter than usual. We will be back next year, rested and restored, on Jan. 3. πŸŽ„ - -> πŸŽ… Happy holidays and a Happy New Year to all, and especially those that have made this year special for Backstage! πŸŽ… - [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CNCF Status](https://img.shields.io/badge/cncf%20status-sandbox-blue.svg)](https://www.cncf.io/projects) [![Main CI Build](https://github.com/backstage/backstage/workflows/Main%20Master%20Build/badge.svg)](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22) diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 9f651ddd1a..803a6babc7 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -129,8 +129,12 @@ function msUntilExpiry(token: string): number { // Calls the specified url regularly using an auth token to set a token cookie // to authorize regular HTTP requests when loading techdocs -async function setTokenCookie(url: string, getIdToken: () => Promise) { - const token = await getIdToken(); +async function setTokenCookie(url: string, identityApi: IdentityApi) { + const { token } = await identityApi.getCredentials(); + if (!token) { + return; + } + await fetch(url, { mode: 'cors', credentials: 'include', @@ -138,11 +142,12 @@ async function setTokenCookie(url: string, getIdToken: () => Promise) { Authorization: `Bearer ${token}`, }, }); + // Call this function again a few minutes before the token expires const ms = msUntilExpiry(token) - 4 * 60 * 1000; setTimeout( () => { - setTokenCookie(url, getIdToken); + setTokenCookie(url, identityApi); }, ms > 0 ? ms : 10000, ); @@ -160,16 +165,13 @@ const app = createApp({ providers={['guest', 'custom', ...providers]} title="Select a sign-in method" align="center" - onResult={async result => { - // When logged in, set a token cookie - if (typeof result.getIdToken !== 'undefined') { - setTokenCookie( - await discoveryApi.getBaseUrl('cookie'), - result.getIdToken, - ); - } - // Forward results - props.onResult(result); + onSignInSuccess={async (identityApi: IdentityApi) => { + setTokenCookie( + await discoveryApi.getBaseUrl('cookie'), + identityApi, + ); + + props.onSignInSuccess(identityApi); }} /> ); diff --git a/contrib/docs/tutorials/quickstart-app-plugin/ExampleFetchComponent.md b/contrib/docs/tutorials/quickstart-app-plugin/ExampleFetchComponent.md index 086175a0ce..f45b70cdb1 100644 --- a/contrib/docs/tutorials/quickstart-app-plugin/ExampleFetchComponent.md +++ b/contrib/docs/tutorials/quickstart-app-plugin/ExampleFetchComponent.md @@ -4,7 +4,7 @@ ExampleFetchComponent.tsx reference ```tsx import React from 'react'; -import { useAsync } from 'react-use'; +import useAsync from 'react-use/lib/useAsync'; import Alert from '@material-ui/lab/Alert'; import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api'; import { Table, TableColumn, Progress } from '@backstage/core-components'; diff --git a/cypress/src/integration/plugins/techdocs.spec.ts b/cypress/src/integration/plugins/techdocs.spec.ts index 0edd7b15ff..d6049ea53d 100644 --- a/cypress/src/integration/plugins/techdocs.spec.ts +++ b/cypress/src/integration/plugins/techdocs.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cypress/src/integration/user/login.spec.ts b/cypress/src/integration/user/login.spec.ts index 25be6e8d4b..8e84ebbf06 100644 --- a/cypress/src/integration/user/login.spec.ts +++ b/cypress/src/integration/user/login.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cypress/src/integration/user/logout.spec.ts b/cypress/src/integration/user/logout.spec.ts index 2d37cb63e5..a3aea9d6a8 100644 --- a/cypress/src/integration/user/logout.spec.ts +++ b/cypress/src/integration/user/logout.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts index 3c8456fcbd..666dc157d7 100644 --- a/cypress/src/support/commands.ts +++ b/cypress/src/support/commands.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 Spotify AB + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/docs/architecture-decisions/adr011-plugin-package-structure.md b/docs/architecture-decisions/adr011-plugin-package-structure.md index 363cae01a5..2def903dfc 100644 --- a/docs/architecture-decisions/adr011-plugin-package-structure.md +++ b/docs/architecture-decisions/adr011-plugin-package-structure.md @@ -35,9 +35,11 @@ We follow this structure for plugin packages (where `x` is the plugin name, for example `catalog` or `techdocs`): - `x`: Contains the main frontend code of the plugin. +- `x-module-`: Contains optional modules related to the frontend plugin + package. - `x-backend`: Contains the main backend code of the plugin. - `x-backend-module-`: Contains optional modules related to the backend - plugin. + plugin package. - `x-react`: Contains shared widgets, hooks and similar that both the plugin itself (`x`) and third-party frontend plugins can depend on. - `x-node`: Contains utilities for backends that both the plugin backend itself diff --git a/docs/architecture-decisions/adr013-use-node-fetch.md b/docs/architecture-decisions/adr013-use-node-fetch.md new file mode 100644 index 0000000000..d802988ae4 --- /dev/null +++ b/docs/architecture-decisions/adr013-use-node-fetch.md @@ -0,0 +1,71 @@ +--- +id: adrs-adr013 +title: 'ADR013: Proper use of HTTP fetching libraries' +# prettier-ignore +description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, node-fetch, and cross-fetch for data fetching. +--- + +## Context + +Using multiple HTTP packages for data fetching increases the complexity and the +support burden of keeping said package up to date. + +## Decision + +Backend (node) packages should use the `node-fetch` package for HTTP data +fetching. Example: + +```ts +import fetch from 'node-fetch'; +import { ResponseError } from '@backstage/errors'; + +const response = await fetch('https://example.com/api/v1/users.json'); +if (!response.ok) { + throw await ResponseError.fromResponse(response); +} +const users = await response.json(); +``` + +Frontend plugins and packages should prefer to use the +[`fetchApiRef`](https://backstage.io/docs/reference/core-plugin-api.fetchapiref). +It uses `cross-fetch` internally. Example: + +```ts +import { useApi } from '@backstage/core-plugin-api'; +const { fetch } = useApi(fetchApiRef); + +const response = await fetch('https://example.com/api/v1/users.json'); +if (!response.ok) { + throw await ResponseError.fromResponse(response); +} +const users = await response.json(); +``` + +Isomorphic packages should have a dependency on the `cross-fetch` package for +mocking and type definitions. Preferably, classes and functions in isomorphic +packages should accept an argument of type `typeof fetch` to let callers supply +their preferred implementation of `fetch`. This lets them adorn the calls with +auth or other information, and track metrics etc, in a cross-platform way. +Example: + +```ts +import crossFetch from 'cross-fetch'; + +export class MyClient { + private readonly fetch: typeof crossFetch; + + constructor(options: { fetch?: typeof crossFetch }) { + this.fetch = options.fetch || crossFetch; + } + + async users() { + return await this.fetch('https://example.com/api/v1/users.json'); + } +} +``` + +## Consequences + +We will gradually transition away from third party packages such as `axios`, +`got` and others. Once we have transitioned to `node-fetch` we will add lint +rules to enforce this decision. diff --git a/docs/assets/architecture-overview/package-architecture.drawio.svg b/docs/assets/architecture-overview/package-architecture.drawio.svg new file mode 100644 index 0000000000..df8c0f8820 --- /dev/null +++ b/docs/assets/architecture-overview/package-architecture.drawio.svg @@ -0,0 +1,746 @@ + + + + + + + + + + + + + + + + + +
+
+
+ app +
+
+
+
+ + app + +
+
+ + + + + + + + + + +
+
+
+ backend +
+
+
+
+ + backend + +
+
+ + + + + + + + + + +
+
+
+ plugin-<plugin-id> +
+
+
+
+ + plugin-<plugin-id> + +
+
+ + + + + + + + + + +
+
+
+ plugin-<plugin-id>-backend +
+
+
+
+ + plugin-<plugin-id>-backend + +
+
+ + + + + + Backend Libraries + + + + + + +
+
+
+ @backstage/backend-common +
+
+
+
+ + @backstage/backend-common + +
+
+ + + + +
+
+
+ @backstage/backend-test-utils +
+
+
+
+ + @backstage/backend-test-utils + +
+
+ + + + +
+
+
+ @backstage/backend-tasks +
+
+
+
+ + @backstage/backend-tasks + +
+
+ + + + + + Common Libraries + + + + + + +
+
+
+ @backstage/catalog-client +
+
+
+
+ + @backstage/catalog-client + +
+
+ + + + +
+
+
+ @backstage/types +
+
+
+
+ + @backstage/types + +
+
+ + + + +
+
+
+ @backstage/config +
+
+
+
+ + @backstage/config + +
+
+ + + + +
+
+
+ @backstage/errors +
+
+
+
+ + @backstage/errors + +
+
+ + + + +
+
+
+ @backstage/catalog-model +
+
+
+
+ + @backstage/catalog-model + +
+
+ + + + +
+
+
+ @backstage/integration +
+
+
+
+ + @backstage/integration + +
+
+ + + + + + Frontend App Core + + + + + + +
+
+
+ @backstage/core-app-api +
+
+
+
+ + @backstage/core-app-api + +
+
+ + + + +
+
+
+ @backstage/app-defaults +
+
+
+
+ + @backstage/app-defaults + +
+
+ + + + + + + + + + + + + +
+
+
+ plugin-<plugin-id>-backend-module-<module-id> +
+
+
+
+ + plugin-<plugin-id>-backend-module-<module-id> + +
+
+ + + + + + + + +
+
+
+ plugin-<plugin-id>-module-<module-id> +
+
+
+
+ + plugin-<plugin-id>-module-<module-id> + +
+
+ + + + + + Common Tooling + + + + + + +
+
+
+ @backstage/cli +
+
+
+
+ + @backstage/cli + +
+
+ + + + + + + + + + External Plugin Libraries + + + + + + +
+
+
+ plugin-<other-plugin-id>-react +
+
+
+
+ + plugin-<other-plugin-id>-react + +
+
+ + + + +
+
+
+ plugin-<other-plugin-id>-common +
+
+
+
+ + plugin-<other-plugin-id>-common + +
+
+ + + + +
+
+
+ plugin-<other-plugin-id>-node +
+
+
+
+ + plugin-<other-plugin-id>-node + +
+
+ + + + + + + + + + + + Plugin Libraries + + + + + + +
+
+
+ plugin-<plugin-id>-react +
+
+
+
+ + plugin-<plugin-id>-react + +
+
+ + + + +
+
+
+ plugin-<plugin-id>-common +
+
+
+
+ + plugin-<plugin-id>-common + +
+
+ + + + +
+
+
+ plugin-<plugin-id>-node +
+
+
+
+ + plugin-<plugin-id>-node + +
+
+ + + + + + + + + Frontend Plugin Core + + + + + + +
+
+
+ @backstage/core-plugin-api +
+
+
+
+ + @backstage/core-plugin-api + +
+
+ + + + +
+
+
+ @backstage/test-utils +
+
+
+
+ + @backstage/test-utils + +
+
+ + + + +
+
+
+ @backstage/dev-utils +
+
+
+
+ + @backstage/dev-utils + +
+
+ + + + + + Frontend Libraries + + + + + + +
+
+
+ @backstage/integration-react +
+
+
+
+ + @backstage/integration-react + +
+
+ + + + +
+
+
+ @backstage/core-components +
+
+
+
+ + @backstage/core-components + +
+
+ + + + +
+
+
+ @backstage/theme +
+
+
+
+ + @backstage/theme + +
+
+ + + + + + + +
+
+
+ Frontend Package +
+
+
+
+ + Frontend Package + +
+
+ + + +
+
+
+ Isomorphic Package +
+
+
+
+ + Isomorphic Package + +
+
+ + + +
+
+
+ Backend Package +
+
+
+
+ + Backend Package + +
+
+ + + + +
+
+
+ CLI Package +
+
+
+
+ + CLI Package + +
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+ Compatibility +
+
+
+
+ + Compatibility + +
+
+ + + + +
+ + + + + Viewer does not support full SVG 1.1 + + + +
diff --git a/docs/auth/bitbucket/provider.md b/docs/auth/bitbucket/provider.md index 63dfb815e0..ee87c2d4e6 100644 --- a/docs/auth/bitbucket/provider.md +++ b/docs/auth/bitbucket/provider.md @@ -50,3 +50,41 @@ The Bitbucket provider is a structure with two configuration keys: To add the provider to the frontend, add the `bitbucketAuthApi` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). + +## Using Bitbucket for sign-in + +In order to use the Bitbucket provider for sign-in, you must configure it with a +`signIn.resolver`. See the +[Sign-In Resolver documentation](../identity-resolver.md) for more details on +how this is done. Note that for the Bitbucket provider, you'll want to use +`bitbucket` as the provider ID, and `createBitbucketProvider` for the provider +factory. + +The `@backstage/plugin-auth-backend` plugin also comes with two built-in +resolves that can be used if desired. The first one is the +`bitbucketUsernameSignInResolver`, which identifies users by matching their +Bitbucket username to `bitbucket.org/username` annotations of `User` entities in +the catalog. Note that you must populate your catalog with matching entities or +users will not be able to sign in. + +The second resolver is the `bitbucketUsernameSignInResolver`, which works the +same way, but uses the Bitbucket user ID instead, and matches on the +`bitbucket.org/user-id` annotation. + +The following is an example of how to use one of the built-in resolvers: + +```ts +import { + createBitbucketProvider, + bitbucketUsernameSignInResolver, +} from '@backstage/plugin-auth-backend'; + +// ... + providerFactories: { + bitbucket: createBitbucketProvider({ + signIn: { + resolver: bitbucketUsernameSignInResolver, + }, + }), + }, +``` diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 32ab830322..492cd86022 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -39,6 +39,7 @@ kubernetes: region: 'europe-west1' skipTLSVerify: true skipMetricsLookup: true + exposeDashboard: true ``` ### `serviceLocatorMethod` @@ -113,9 +114,13 @@ kubectl -n get secret $(kubectl -n get sa ``` + +## How to limit what can be searched in the Software Catalog + +The Software Catalog includes a wealth of information about the components, +systems, groups, users, and other aspects of your software ecosystem. However, +you may not always want _every_ aspect to appear when a user searches the +catalog. Examples include: + +- Entities of kind `Location`, which are often not useful to Backstage users. +- Entities of kind `User` or `Group`, if you'd prefer that users and groups be + exposed to search in a different way (or not at all). + +It's possible to write your own [Collator](./concepts.md#collators) to control +exactly what's available to search, (or a [Decorator](./concepts.md#decorators) +to filter things out here and there), but the `DefaultCatalogCollator` that's +provided by `@backstage/plugin-catalog-backend` offers some configuration too! + +```diff +// packages/backend/src/plugins/search.ts + +indexBuilder.addCollator({ + defaultRefreshIntervalSeconds: 600, + collator: DefaultCatalogCollator.fromConfig(config, { + discovery, + tokenManager, ++ filter: { ++ kind: ['API', 'Component', 'Domain', 'Group', 'System', 'User'], ++ }, + }), +}); +``` + +As shown above, you can add a catalog entity filter to narrow down what catalog +entities are indexed by the search engine. diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md index e80e8a1842..821f39ff6e 100644 --- a/docs/features/software-catalog/catalog-customization.md +++ b/docs/features/software-catalog/catalog-customization.md @@ -10,8 +10,7 @@ and find catalog entities. This is already set up by default by `@backstage/create-app`. If you want to change the default index page - such as to add a custom filter to -the catalog - you can replace the routing in `App.tsx` to point to your own -`CatalogIndexPage`. +the catalog - you can create your own `CatalogIndexPage`. > Note: The catalog index page is designed to have a minimal code footprint to > support easy customization, but creating a copy does introduce a possibility @@ -21,23 +20,25 @@ the catalog - you can replace the routing in `App.tsx` to point to your own For example, suppose that I want to allow filtering by a custom annotation added to entities, `company.com/security-tier`. To start, I'll copy the code for the -default catalog page and create a component in a -[new plugin](../../plugins/create-a-plugin.md): +default catalog page and create a component. ```tsx // imports, etc omitted for brevity. for full source see: -// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx export const CustomCatalogPage = ({ columns, actions, initiallySelectedFilter = 'owned', }: CatalogPageProps) => { + const createComponentLink = useRouteRef( + catalogPlugin.externalRoutes.createComponent, + ); return ( }> - + All your software catalog entities @@ -167,21 +168,7 @@ export const CustomCatalogPage = ({ }; ``` -This page itself can be exported as a routable extension in the plugin: - -```ts -export const CustomCatalogIndexPage = myPlugin.provide( - createRoutableExtension({ - name: 'CustomCatalogIndexPage', - component: () => - import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage), - mountPoint: catalogRouteRef, - }), -); -``` - -Finally, we can replace the catalog route in the Backstage application with our -new `CustomCatalogIndexPage`. +Finally, we can apply our new `CustomCatalogPage`. ```diff # packages/app/src/App.tsx @@ -189,7 +176,9 @@ const routes = ( - } /> -+ } /> ++ }> ++ ++ ``` The same method can be used to customize the _default_ filters with a different diff --git a/docs/features/techdocs/configuring-ci-cd.md b/docs/features/techdocs/configuring-ci-cd.md index 0dec7ec24e..96d841eadf 100644 --- a/docs/features/techdocs/configuring-ci-cd.md +++ b/docs/features/techdocs/configuring-ci-cd.md @@ -10,7 +10,7 @@ TechDocs reads the static generated documentation files from a cloud storage bucket (GCS, AWS S3, etc.). The documentation site is generated on the CI/CD workflow associated with the repository containing the documentation files. This document explains the steps needed to generate docs on CI and publish to a cloud -storage using [`techdocs-cli`](https://github.com/backstage/techdocs-cli). +storage using [`techdocs-cli`](./cli.md). The steps here target all kinds of CI providers (GitHub Actions, CircleCI, Jenkins, etc.). Specific tools for individual providers will also be made @@ -40,9 +40,8 @@ techdocs-cli publish --publisher-type awsS3 --storage-name -- That's it! -Take a look at -[`techdocs-cli` README](https://github.com/backstage/techdocs-cli) for the -complete command reference, details, and options. +Take a look at [`techdocs-cli`](./cli.md) for the complete command reference, +details, and options. ## Steps @@ -74,7 +73,7 @@ Install [`npx`](https://www.npmjs.com/package/npx) to use it for running `techdocs-cli`. Or you can install using `npm install -g @techdocs/cli`. We are going to use the -[`techdocs-cli generate`](https://github.com/backstage/techdocs-cli#generate-techdocs-site-from-a-documentation-project) +[`techdocs-cli generate`](./cli.md#generate-techdocs-site-from-a-documentation-project) command in this step. ```sh @@ -93,8 +92,7 @@ necessary authentication environment variables. - [AWS authentication](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html) And then run the -[`techdocs-cli publish`](https://github.com/backstage/techdocs-cli#publish-generated-techdocs-sites) -command. +[`techdocs-cli publish`](./cli.md#publish-generated-techdocs-sites) command. ```sh npx @techdocs/cli publish --publisher-type --storage-name --entity --directory ./site diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index d79f6bb891..37e135d1dc 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -230,7 +230,7 @@ You can do so by including the following lines in the last step of your ```Dockerfile RUN apt-get update && apt-get install -y python3 python3-pip -RUN pip3 install mkdocs-techdocs-core==0.0.16 +RUN pip3 install mkdocs-techdocs-core==0.2.2 ``` Please be aware that the version requirement could change, you need to check our diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index 8ff486af37..d9a8ffb93a 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -421,3 +421,24 @@ folder (/docs) or replace the content in this file. > on how you have configured your `template.yaml` Done! You now have support for TechDocs in your own software template! + +## how to enable iframes in TechDocs + +Techdocs uses the [DOMPurify](https://github.com/cure53/DOMPurify) to sanitizes +HTML and prevents XSS attacks + +It's possible to allow some iframes based on a list of allowed hosts. To do +this, add the allowed hosts in the `techdocs.sanitizer.allowedIframeHosts` +configuration of your `app-config.yaml` + +E.g. + +```yaml +techdocs: + sanitizer: + allowedIframeHosts: + - drive.google.com +``` + +This way, all iframes where the host of src attribute is in the +`sanitizer.allowedIframeHosts` list will be displayed diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index a4ca0771df..d05a14cc35 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -53,8 +53,10 @@ To add a custom theme to your Backstage app, you pass it as configuration to For example, adding the theme that we created in the previous section can be done like this: -```ts +```tsx import { createApp } from '@backstage/app-defaults'; +import { ThemeProvider } from '@material-ui/core/styles'; +import CssBaseline from '@material-ui/core/CssBaseline'; const app = createApp({ apis: ..., @@ -63,7 +65,11 @@ const app = createApp({ id: 'my-theme', title: 'My Custom Theme', variant: 'light', - theme: myTheme, + Provider: ({ children }) => ( + + {children} + + ), }] }) ``` @@ -76,60 +82,67 @@ want to use the default themes, they are exported as `lightTheme` and ## Example of a custom theme ```ts -const themeOptions = createThemeOptions({ +import { + createTheme, + genPageTheme, + lightTheme, + shapes, +} from '@backstage/theme'; + +const myTheme = createTheme({ palette: { ...lightTheme.palette, primary: { - main: '#123456', + main: '#343b58', }, secondary: { - main: '#123456', + main: '#565a6e', }, error: { - main: '#123456', + main: '#8c4351', }, warning: { - main: '#123456', + main: '#8f5e15', }, info: { - main: '#123456', + main: '#34548a', }, success: { - main: '#123456', + main: '#485e30', }, background: { - default: '#123456', - paper: '#123456', + default: '#d5d6db', + paper: '#d5d6db', }, banner: { - info: '#123456', - error: '#123456', - text: '#123456', - link: '#123456', + info: '#34548a', + error: '#8c4351', + text: '#343b58', + link: '#565a6e', }, - errorBackground: '#123456', - warningBackground: '#123456', - infoBackground: '#123456', + errorBackground: '#8c4351', + warningBackground: '#8f5e15', + infoBackground: '#343b58', navigation: { - background: '#123456', - indicator: '#123456', - color: '#123456', - selectedColor: '#123456', + background: '#343b58', + indicator: '#8f5e15', + color: '#d5d6db', + selectedColor: '#ffffff', }, }, defaultPageTheme: 'home', - fontFamily: 'Comic Sans', + fontFamily: 'Comic Sans MS', /* below drives the header colors */ pageTheme: { - home: genPageTheme(['#123456', '#123456'], shapes.wave), - documentation: genPageTheme(['#123456', '#123456'], shapes.wave2), - tool: genPageTheme(['#123456', '#123456'], shapes.round), - service: genPageTheme(['#123456', '#123456'], shapes.wave), - website: genPageTheme(['#123456', '#123456'], shapes.wave), - library: genPageTheme(['#123456', '#123456'], shapes.wave), - other: genPageTheme(['#123456', '#123456'], shapes.wave), - app: genPageTheme(['#123456', '#123456'], shapes.wave), - apis: genPageTheme(['#123456', '#123456'], shapes.wave), + home: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + documentation: genPageTheme(['#8c4351', '#343b58'], shapes.wave2), + tool: genPageTheme(['#8c4351', '#343b58'], shapes.round), + service: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + website: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + library: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + other: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + app: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + apis: genPageTheme(['#8c4351', '#343b58'], shapes.wave), }, }); ``` @@ -162,7 +175,7 @@ wouldn't be enough to alter the `box-shadow` property or to add css rules that aren't already defined like a margin. For these cases you should also create an override. -```ts +```tsx import { createApp } from '@backstage/core-app-api'; import { BackstageTheme, lightTheme } from '@backstage/theme'; /** @@ -187,6 +200,16 @@ export const createCustomThemeOverrides = ( }; }; +const customTheme: BackstageTheme = { + ...lightTheme, + overrides: { + // These are the overrides that Backstage applies to `material-ui` components + ...lightTheme.overrides, + // These are your custom overrides, either to `material-ui` or Backstage components. + ...createCustomThemeOverrides(lightTheme), + }, +}; + const app = createApp({ apis: ..., plugins: ..., @@ -194,15 +217,11 @@ const app = createApp({ id: 'my-theme', title: 'My Custom Theme', variant: 'light', - theme: { - ...lightTheme, - overrides: { - // These are the overrides that Backstage applies to `material-ui` components - ...lightTheme.overrides, - // These are your custom overrides, either to `material-ui` or Backstage components. - ...createCustomThemeOverrides(lightTheme), - }, - }, + Provider: ({ children }) => ( + + {children} + + ), }] }); ``` @@ -234,3 +253,73 @@ const LogoFull = () => { return ; }; ``` + +## Custom Homepage + +In addition to a custom theme, a custom logo, you can also customize the +homepage of your app. To do that we need to go through a few steps. + +### Setting up the Home Page + +1. Create a Home Page Component that will be used for composition. + +`packages/app/src/components/home/HomePage.tsx` + +```tsx +import React from 'react'; + +export const HomePage = () => { + return { + /* TODO: Compose a Home Page here */ + }; +}; +``` + +2. Add a route where the homepage will live, presumably `/`. + +`packages/app/src/App.tsx` + +```tsx +import { HomepageCompositionRoot } from '@backstage/plugin-home'; +import { HomePage } from './components/home/HomePage'; + +// ... +}> + +; +// ... +``` + +### Composing your Home Page + +Composing a Home Page is no different from creating a regular React Component, +i.e. the App Integrator is free to include whatever content they like. However, +there are components developed with the Home Page in mind. If you are looking +for components to use when composing your homepage, you can take a look at the +[collection of Homepage components](https://backstage.io/?path=/story/plugins-home-components) +in storybook. If you don't find a component that suits your needs but want to +contribute, check the +[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing). + +!!! tip If you want to use one of the available homepage templates you can find +the +[templates](https://backstage.io/storybook/?path=/story/plugins-home-templates) +in the storybook under the "Home" plugin. And if you would like to contribute a +template, please see the +[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing) + +```tsx +import React from 'react'; +import Grid from '@material-ui/core/Grid'; +import { HomePageCompanyLogo } from '@backstage/plugin-home'; + +export const HomePage = () => { + return ( + + + + + + ); +}; +``` diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index bcb792e7aa..55285e7f4e 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -215,7 +215,7 @@ days for expiration. If you have a hard time picking a number, we suggest to go for 7 days, it's a lucky number.

- Screenshot of the GitHub OAuth creation page + Screenshot of the GitHub Personal Access Token creation page

Set the scope to your likings. For this tutorial, selecting "repo" should be diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md index ffe4f4dcd5..107119aace 100644 --- a/docs/getting-started/keeping-backstage-updated.md +++ b/docs/getting-started/keeping-backstage-updated.md @@ -22,6 +22,13 @@ yarn backstage-cli versions:bump The reason for bumping all `@backstage` packages at once is to maintain the dependencies that they have between each other. +If you are using other plugins you can pass in the `--pattern` option to update +more than just the `@backstage/*` dependencies. + +```bash +yarn backstage-cli versions:bump --pattern '@{backstage,roadiehq}/*' +``` + ## Following create-app template changes The `@backstage/create-app` command creates the initial structure of your diff --git a/docs/integrations/aws-s3/locations.md b/docs/integrations/aws-s3/locations.md index fe1c6050c2..b0c6829e2c 100644 --- a/docs/integrations/aws-s3/locations.md +++ b/docs/integrations/aws-s3/locations.md @@ -20,8 +20,7 @@ To use this integration, add configuration to your `app-config.yaml`: ```yaml integrations: awsS3: - - host: amazonaws.com - accessKeyId: ${AWS_ACCESS_KEY_ID} + - accessKeyId: ${AWS_ACCESS_KEY_ID} secretAccessKey: ${AWS_SECRET_ACCESS_KEY} ``` @@ -35,8 +34,21 @@ instruct the AWS S3 reader to assume a role before accessing S3: ```yaml integrations: awsS3: - - host: amazonaws.com - accessKeyId: ${AWS_ACCESS_KEY_ID} + - accessKeyId: ${AWS_ACCESS_KEY_ID} secretAccessKey: ${AWS_SECRET_ACCESS_KEY} roleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/example-role' ``` + +Configuration allows specifying custom S3 endpoint, along with +[path-style access](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html) +to support integration with providers like +[LocalStack](https://github.com/localstack/localstack): + +```yaml +integrations: + awsS3: + - endpoint: 'http://localhost:4566' + s3ForcePathStyle: true + accessKeyId: ${AWS_ACCESS_KEY_ID} + secretAccessKey: ${AWS_SECRET_ACCESS_KEY} +``` diff --git a/docs/local-dev/cli-commands.md b/docs/local-dev/cli-commands.md index 318b37f34e..caec60ed70 100644 --- a/docs/local-dev/cli-commands.md +++ b/docs/local-dev/cli-commands.md @@ -434,7 +434,8 @@ Usage: backstage-cli build [options] Options: --outputs <formats> List of formats to output [types,cjs,esm] - -h, --help display help for command + --minify Minify the generated code + -h, --help display help for command ``` ## lint @@ -593,6 +594,7 @@ Usage: backstage-cli versions:bump [options] Options: -h, --help display help for command + -p, --pattern Override glob for matching packages to upgrade ``` ## versions:check diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index 3425b02db9..d3f171e4f8 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -164,12 +164,104 @@ https://circleci.com. ![CircleCI plugin talking to proxy talking to SaaS Circle CI](../assets/architecture-overview/circle-ci-plugin-architecture.png) +## Package Architecture + +Backstage relies heavily on NPM packages, both for distribution of libraries, +and structuring of code within projects. While the way you structure your +Backstage project is up to you, there is a set of established patterns that we +encourage you to follow. These patterns can help set up a sound project +structure as well as provide familiarity between different Backstage projects. + +The following diagram shows an overview of the package architecture of +Backstage. It takes the point of view of an individual plugin and all of the +packages that it may contain, indicated by the thicker border and italic text. +Surrounding the plugin are different package groups which are the different +possible interface points of the plugin. Note that not all library package lists +are complete as packages have been omitted for brevity. + +![Package architecture](../assets/architecture-overview/package-architecture.drawio.svg) + +### Overview + +The arrows in the diagram above indicate a runtime dependency on the code of the +target package. This strict dependency graph only applies to runtime +`dependencies`, and there may be `devDependencies` that break the rules of this +table for the purpose of testing. While there are some arrows that show a +dependency on a collection of frontend, backend and isomorphic packages, those +still have to abide by important compatibility rules shown in the bottom left. + +The `app` and `backend` packages are the entry points of a Backstage project. +The `app` package is the frontend application that brings together a collection +of frontend plugins and customizes them to fit an organization, while the +`backend` package is the backend service that powers the Backstage application. +Worth noting is that there can be more than one instance of each of these +packages within a project. Particularly the `backend` packages can benefit from +being split up into smaller deployment units that each serve their own purpose +with a smaller collection of plugins. + +### Plugin Packages + +A typical plugin consists of up to five packages, two frontend ones, two +backend, and one isomorphic packages. All packages within the plugin must share +a common prefix, typically of the form `@/plugin-`, but +alternatives like `backstage-plugin-` or +`@scope/backstage-plugin-` are also valid. Along with this prefix, +each of the packages have their own unique suffix that denotes their role. In +addition to these five plugin packages it's also possible for to a plugin to +have additional frontend and backend modules that can be installed to enable +optional features. For a full list of suffixes and their roles, see the +[Plugin Package Structure ADR](../architecture-decisions/adr011-plugin-package-structure.md). + +The `-react`, `-common`, and `-node` plugin packages together form the external +library of a plugin. The plugin library enables other plugins to build on top of +and extend a plugin, and likewise allows the plugin to depend on and extend +other plugins. Because of this, it is preferable that plugin library packages +allow duplicate installations of themselves, as you may end up with a mix of +versions being installed as dependencies of various plugins. It is also +forbidden for plugins to directly import non-library packages from other +plugins, all communication between plugins must be handled through libraries and +the application itself. + +### Frontend Packages + +The frontend packages are grouped into two main groups. The first one is +"Frontend App Core", which is the set of packages that are only used by the +`app` package itself. These packages help build up the core structure of the app +as well as provide a foundation for the plugin libraries to rely upon. + +The second group is the rest of the shared packages, further divided into +"Frontend Plugin Core" and "Frontend Libraries". The core packages that are +considered particularly stable and form the core of the frontend framework. +Their most important role is to form the boundary around each plugin and provide +a set of tools that helps you combine a collection of plugins into a running +application. The rest of the frontend packages are more traditional libraries +that serve as building blocks to create plugins. + +### Backend Packages + +The backend library packages do not currently share a similar plugin +architecture as the frontend packages. They are instead simply a collection of +building blocks and patterns that help you build backend services. This is +however likely to change in the future. + +### Common Packages + +The common packages are the packages are effectively depended on by all other +pages. This is a much smaller set of packages but they are also very pervasive. +Because the common packages are isomorphic and must execute both in the frontend +and backend, they are never allowed to depend on any of the frontend of backend +packages. + +The Backstage CLI is in a category of its own and is depended on by virtually +all other packages. It's not a library in itself though, and must always be a +development dependency only. + ## Databases As we have seen, both the `lighthouse-audit-service` and `catalog-backend` require a database to work with. -The Backstage backend and its builtin plugins are based on the +The Backstage backend and its built-in plugins are based on the [Knex](http://knexjs.org/) library, and set up a separate logical database per plugin. This gives great isolation and lets them perform migrations and evolve separate from each other. @@ -184,7 +276,7 @@ yet. ## Cache -The Backstage backend and its builtin plugins are also able to leverage cache +The Backstage backend and its built-in plugins are also able to leverage cache stores as a means of improving performance or reliability. Similar to how databases are supported, plugins receive logically separated cache connections, which are powered by [Keyv](https://github.com/lukechilds/keyv) under the hood. diff --git a/docs/plugins/analytics.md b/docs/plugins/analytics.md index ace9a89968..7fbd256e86 100644 --- a/docs/plugins/analytics.md +++ b/docs/plugins/analytics.md @@ -55,10 +55,11 @@ learn how to contribute the integration yourself! The following table summarizes events that, depending on the plugins you have installed, may be captured. -| Action | Provided By | Subject | -| ---------- | -------------- | ----------------------------------------- | -| `navigate` | Backstage Core | The URL of the page that was navigated to | -| `click` | Backstage Core | The text of the link that was clicked on | +| Action | Provided By | Subject | +| ---------- | -------------- | --------------------------------------------------- | +| `navigate` | Backstage Core | The URL of the page that was navigated to | +| `click` | Backstage Core | The text of the link that was clicked on | +| `search` | Backstage Core | The search term entered in any search bar component | If there is an event you'd like to see captured, please [open an issue][add-event] describing the event you want to see and the questions it diff --git a/docs/tutorials/quickstart-app-plugin.md b/docs/tutorials/quickstart-app-plugin.md index 938a57198a..d1ca61a11f 100644 --- a/docs/tutorials/quickstart-app-plugin.md +++ b/docs/tutorials/quickstart-app-plugin.md @@ -135,7 +135,7 @@ changes, let's start by wiping this component clean. ```tsx import React from 'react'; -import { useAsync } from 'react-use'; +import useAsync from 'react-use/lib/useAsync'; import Alert from '@material-ui/lab/Alert'; import { Table, TableColumn, Progress } from '@backstage/core-components'; import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api'; diff --git a/microsite/data/plugins/airbrake.yaml b/microsite/data/plugins/airbrake.yaml new file mode 100644 index 0000000000..96de75c002 --- /dev/null +++ b/microsite/data/plugins/airbrake.yaml @@ -0,0 +1,9 @@ +--- +title: Airbrake +author: Simply Business +authorUrl: https://github.com/simplybusiness/ +category: Monitoring +description: Access Airbrake error monitoring and other integrations from within Backstage +documentation: https://github.com/backstage/backstage/blob/master/plugins/airbrake/README.md +iconUrl: https://wp-assets.airbrake.io/wp-content/uploads/2020/10/05222904/Square-white-A-on-Orange.png +npmPackageName: '@backstage/plugin-airbrake' diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 4750e1d49d..6c4c5261d9 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -287,7 +287,8 @@ "architecture-decisions/adrs-adr009", "architecture-decisions/adrs-adr010", "architecture-decisions/adrs-adr011", - "architecture-decisions/adrs-adr012" + "architecture-decisions/adrs-adr012", + "architecture-decisions/adrs-adr013" ], "FAQ": ["FAQ"] } diff --git a/mkdocs.yml b/mkdocs.yml index 625236f737..81dad55b84 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -186,6 +186,8 @@ nav: - ADR009 - Entity References: 'architecture-decisions/adr009-entity-references.md' - ADR010 - Luxon Date Library: 'architecture-decisions/adr010-luxon-date-library.md' - ADR011 - Plugin Package Structure: 'architecture-decisions/adr011-plugin-package-structure.md' + - ADR012 - Plugin Package Structure: 'architecture-decisions/adr012-use-luxon-locale-and-date-presets.md' + - ADR013 - Plugin Package Structure: 'architecture-decisions/adr013-use-node-fetch.md' - Support: - Backstage Project Structure: 'support/project-structure.md' - Glossary: glossary.md diff --git a/package.json b/package.json index 57cf603090..fe5876dd97 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "start": "yarn workspace example-app start", "start-backend": "yarn workspace example-backend start", "build": "lerna run build", - "build:api-reports": "yarn tsc:full && yarn build:api-reports:only", + "build:api-reports": "yarn build:api-reports:only --tsc", "build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts", "build:api-docs": "yarn build:api-reports --docs", "tsc": "tsc", @@ -55,6 +55,7 @@ }, "version": "1.0.0", "dependencies": { + "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.13.77", "@microsoft/api-extractor": "^7.19.2", "@microsoft/api-extractor-model": "^7.15.1", @@ -68,7 +69,7 @@ "@types/webpack": "^5.28.0", "command-exists": "^1.2.9", "cross-env": "^7.0.0", - "concurrently": "^6.0.0", + "concurrently": "^7.0.0", "eslint-plugin-notice": "^0.9.10", "fs-extra": "9.1.0", "husky": "^6.0.0", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 5465c6b9e7..c14db343bc 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,49 @@ # example-app +## 0.2.59 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.10.5 + - @backstage/plugin-search@0.5.4 + - @backstage/plugin-techdocs@0.12.13 + - @backstage/core-plugin-api@0.4.1 + - @backstage/plugin-catalog-react@0.6.10 + - @backstage/plugin-kubernetes@0.5.3 + - @backstage/core-app-api@0.3.1 + - @backstage/core-components@0.8.3 + - @backstage/plugin-apache-airflow@0.1.2 + - @backstage/plugin-azure-devops@0.1.9 + - @backstage/plugin-badges@0.2.18 + - @backstage/plugin-catalog@0.7.7 + - @backstage/plugin-catalog-graph@0.2.5 + - @backstage/plugin-catalog-import@0.7.8 + - @backstage/plugin-circleci@0.2.33 + - @backstage/plugin-cloudbuild@0.2.31 + - @backstage/plugin-code-coverage@0.1.21 + - @backstage/plugin-cost-insights@0.11.16 + - @backstage/plugin-explore@0.3.24 + - @backstage/plugin-gcp-projects@0.3.12 + - @backstage/plugin-github-actions@0.4.30 + - @backstage/plugin-graphiql@0.2.26 + - @backstage/plugin-home@0.4.9 + - @backstage/plugin-jenkins@0.5.16 + - @backstage/plugin-kafka@0.2.24 + - @backstage/plugin-lighthouse@0.2.33 + - @backstage/plugin-newrelic@0.3.12 + - @backstage/plugin-newrelic-dashboard@0.1.2 + - @backstage/plugin-org@0.3.33 + - @backstage/plugin-pagerduty@0.3.21 + - @backstage/plugin-rollbar@0.3.22 + - @backstage/plugin-scaffolder@0.11.17 + - @backstage/plugin-sentry@0.3.32 + - @backstage/plugin-shortcuts@0.1.18 + - @backstage/plugin-tech-insights@0.1.4 + - @backstage/plugin-tech-radar@0.5.1 + - @backstage/plugin-user-settings@0.3.15 + - @backstage/plugin-api-docs@0.6.21 + ## 0.2.58 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 1dd48eb7bd..bbfd903484 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,60 +1,61 @@ { "name": "example-app", - "version": "0.2.58", + "version": "0.2.59", "private": true, "bundled": true, "dependencies": { "@backstage/app-defaults": "^0.1.3", "@backstage/catalog-model": "^0.9.8", - "@backstage/cli": "^0.10.3", - "@backstage/core-app-api": "^0.3.0", - "@backstage/core-components": "^0.8.2", - "@backstage/core-plugin-api": "^0.4.0", + "@backstage/cli": "^0.10.5", + "@backstage/core-app-api": "^0.3.1", + "@backstage/core-components": "^0.8.3", + "@backstage/core-plugin-api": "^0.4.1", "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-api-docs": "^0.6.19", - "@backstage/plugin-azure-devops": "^0.1.8", - "@backstage/plugin-apache-airflow": "^0.1.1", - "@backstage/plugin-badges": "^0.2.17", - "@backstage/plugin-catalog": "^0.7.5", - "@backstage/plugin-catalog-graph": "^0.2.4", - "@backstage/plugin-catalog-import": "^0.7.6", - "@backstage/plugin-catalog-react": "^0.6.8", - "@backstage/plugin-circleci": "^0.2.32", - "@backstage/plugin-cloudbuild": "^0.2.30", - "@backstage/plugin-code-coverage": "^0.1.20", - "@backstage/plugin-cost-insights": "^0.11.14", - "@backstage/plugin-explore": "^0.3.23", - "@backstage/plugin-gcp-projects": "^0.3.11", - "@backstage/plugin-github-actions": "^0.4.28", - "@backstage/plugin-graphiql": "^0.2.25", - "@backstage/plugin-home": "^0.4.8", - "@backstage/plugin-jenkins": "^0.5.15", - "@backstage/plugin-kafka": "^0.2.23", - "@backstage/plugin-kubernetes": "^0.5.2", - "@backstage/plugin-lighthouse": "^0.2.32", - "@backstage/plugin-newrelic": "^0.3.11", - "@backstage/plugin-newrelic-dashboard": "^0.1.1", - "@backstage/plugin-org": "^0.3.32", - "@backstage/plugin-pagerduty": "0.3.20", - "@backstage/plugin-rollbar": "^0.3.21", - "@backstage/plugin-scaffolder": "^0.11.15", - "@backstage/plugin-search": "^0.5.2", - "@backstage/plugin-sentry": "^0.3.31", - "@backstage/plugin-shortcuts": "^0.1.16", - "@backstage/plugin-tech-radar": "^0.5.0", - "@backstage/plugin-techdocs": "^0.12.11", + "@backstage/plugin-airbrake": "^0.0.0", + "@backstage/plugin-api-docs": "^0.6.21", + "@backstage/plugin-azure-devops": "^0.1.9", + "@backstage/plugin-apache-airflow": "^0.1.2", + "@backstage/plugin-badges": "^0.2.18", + "@backstage/plugin-catalog": "^0.7.7", + "@backstage/plugin-catalog-graph": "^0.2.5", + "@backstage/plugin-catalog-import": "^0.7.8", + "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/plugin-circleci": "^0.2.33", + "@backstage/plugin-cloudbuild": "^0.2.31", + "@backstage/plugin-code-coverage": "^0.1.21", + "@backstage/plugin-cost-insights": "^0.11.16", + "@backstage/plugin-explore": "^0.3.24", + "@backstage/plugin-gcp-projects": "^0.3.12", + "@backstage/plugin-github-actions": "^0.4.30", + "@backstage/plugin-graphiql": "^0.2.26", + "@backstage/plugin-home": "^0.4.9", + "@backstage/plugin-jenkins": "^0.5.16", + "@backstage/plugin-kafka": "^0.2.24", + "@backstage/plugin-kubernetes": "^0.5.3", + "@backstage/plugin-lighthouse": "^0.2.33", + "@backstage/plugin-newrelic": "^0.3.12", + "@backstage/plugin-newrelic-dashboard": "^0.1.2", + "@backstage/plugin-org": "^0.3.33", + "@backstage/plugin-pagerduty": "0.3.21", + "@backstage/plugin-rollbar": "^0.3.22", + "@backstage/plugin-scaffolder": "^0.11.17", + "@backstage/plugin-search": "^0.5.4", + "@backstage/plugin-sentry": "^0.3.32", + "@backstage/plugin-shortcuts": "^0.1.18", + "@backstage/plugin-tech-radar": "^0.5.1", + "@backstage/plugin-techdocs": "^0.12.13", "@backstage/plugin-todo": "^0.1.17", - "@backstage/plugin-user-settings": "^0.3.14", + "@backstage/plugin-user-settings": "^0.3.15", "@backstage/search-common": "^0.2.0", - "@backstage/plugin-tech-insights": "^0.1.2", + "@backstage/plugin-tech-insights": "^0.1.4", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "@roadiehq/backstage-plugin-github-insights": "^1.2.2", - "@roadiehq/backstage-plugin-github-pull-requests": "^1.0.13", - "@roadiehq/backstage-plugin-travis-ci": "^1.0.11", + "@roadiehq/backstage-plugin-github-insights": "^1.4.2", + "@roadiehq/backstage-plugin-github-pull-requests": "^1.3.2", + "@roadiehq/backstage-plugin-travis-ci": "^1.3.2", "history": "^5.0.0", "prop-types": "^15.7.2", "react": "^16.13.1", diff --git a/packages/app/public/index.html b/packages/app/public/index.html index 8273576b01..885fb6c228 100644 --- a/packages/app/public/index.html +++ b/packages/app/public/index.html @@ -42,11 +42,6 @@ href="<%= publicPath %>/safari-pinned-tab.svg" color="#5bbad5" /> - <%= config.getString('app.title') %> <% if (config.has('app.googleAnalyticsTrackingId')) { %> @@ -103,7 +98,7 @@ <% } %> - +
- * + * ``` * - * @deprecated Use plain MUI and composable helpers instead. + * @deprecated Use plain MUI `` and composable helpers instead. * @see https://material-ui.com/components/cards/ */ export function ItemCard(props: ItemCardProps) { diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 511a51fd9c..7b2c5fa4d7 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -21,7 +21,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import React, { useContext, useState } from 'react'; -import { useLocalStorage } from 'react-use'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import { sidebarConfig, SidebarContext, diff --git a/packages/core-components/src/layout/SignInPage/SignInPage.tsx b/packages/core-components/src/layout/SignInPage/SignInPage.tsx index 304e427f33..2eac16cbf4 100644 --- a/packages/core-components/src/layout/SignInPage/SignInPage.tsx +++ b/packages/core-components/src/layout/SignInPage/SignInPage.tsx @@ -25,7 +25,7 @@ import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import React, { useState } from 'react'; -import { useMount } from 'react-use'; +import useMount from 'react-use/lib/useMount'; import { Progress } from '../../components/Progress'; import { Content } from '../Content/Content'; import { ContentHeader } from '../ContentHeader/ContentHeader'; diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 0bbbf4d205..535be6aef6 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-plugin-api +## 0.4.1 + +### Patch Changes + +- c534ef2242: Deprecated `OldIconComponent`. Existing usage should be replaced with `IconComponent`. + ## 0.4.0 ### Minor Changes diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 928a90cee5..de25d24660 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -16,7 +16,6 @@ import { ProfileInfo as ProfileInfo_2 } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import { ReactElement } from 'react'; import { ReactNode } from 'react'; -import { SvgIconProps } from '@material-ui/core'; // @public export type AlertApi = { @@ -241,7 +240,6 @@ export type BackstagePlugin< ExternalRoutes extends AnyExternalRoutes = {}, > = { getId(): string; - output(): PluginOutput[]; getApis(): Iterable; getFeatureFlags(): Iterable; provide(extension: Extension): T; @@ -446,12 +444,6 @@ export type FeatureFlag = { pluginId: string; }; -// @public @deprecated -export type FeatureFlagOutput = { - type: 'feature-flag'; - name: string; -}; - // @public export interface FeatureFlagsApi { getRegisteredFlags(): FeatureFlag[]; @@ -623,9 +615,6 @@ export const oktaAuthApiRef: ApiRef< SessionApi >; -// @public -export type OldIconComponent = ComponentType; - // @alpha export const oneloginAuthApiRef: ApiRef< OAuthApi & @@ -687,7 +676,6 @@ export type PluginConfig< > = { id: string; apis?: Iterable; - register?(hooks: PluginHooks): void; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; @@ -698,14 +686,6 @@ export type PluginFeatureFlagConfig = { name: string; }; -// @public @deprecated -export type PluginHooks = { - featureFlags: FeatureFlagsHooks; -}; - -// @public @deprecated -export type PluginOutput = FeatureFlagOutput; - // @public export type ProfileInfo = { email?: string; diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index fbb6c51c1e..d284d60c6b 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "0.4.0", + "version": "0.4.1", "private": false, "publishConfig": { "access": "public", @@ -30,10 +30,8 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", - "@material-ui/core": "^4.12.2", "history": "^5.0.0", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", @@ -45,8 +43,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/core-app-api": "^0.3.0", + "@backstage/cli": "^0.10.5", + "@backstage/core-app-api": "^0.3.1", "@backstage/test-utils": "^0.2.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/packages/core-plugin-api/src/icons/index.ts b/packages/core-plugin-api/src/icons/index.ts index de79dd08d3..9c9e45e54c 100644 --- a/packages/core-plugin-api/src/icons/index.ts +++ b/packages/core-plugin-api/src/icons/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { IconComponent, OldIconComponent } from './types'; +export type { IconComponent } from './types'; diff --git a/packages/core-plugin-api/src/icons/types.ts b/packages/core-plugin-api/src/icons/types.ts index 5648261f3c..d7dca27bf9 100644 --- a/packages/core-plugin-api/src/icons/types.ts +++ b/packages/core-plugin-api/src/icons/types.ts @@ -15,7 +15,6 @@ */ import { ComponentType } from 'react'; -import { SvgIconProps } from '@material-ui/core'; /** * IconComponent is the common icon type used throughout Backstage when @@ -36,12 +35,3 @@ import { SvgIconProps } from '@material-ui/core'; export type IconComponent = ComponentType<{ fontSize?: 'default' | 'small' | 'large'; }>; - -/** - * This exists for backwards compatibility with the old core package. - * It's used in some parts of this package in order to smooth out the - * migration, but it is not exported. - * - * @public - */ -export type OldIconComponent = ComponentType; diff --git a/packages/core-plugin-api/src/plugin/Plugin.test.tsx b/packages/core-plugin-api/src/plugin/Plugin.test.tsx index d3758543a1..b66235e210 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.test.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.test.tsx @@ -28,62 +28,7 @@ describe('Plugin Feature Flag', () => { expect( createPlugin({ id: 'test', - register({ featureFlags }) { - featureFlags.register('blob'); - }, }).getFeatureFlags(), - ).toEqual([{ name: 'blob' }]); - - expect( - createPlugin({ - id: 'test', - register({ featureFlags }) { - featureFlags.register('blob'); - }, - featureFlags: [{ name: 'test' }], - }).getFeatureFlags(), - ).toEqual([{ name: 'test' }, { name: 'blob' }]); - - expect( - createPlugin({ - id: 'test', - }).getFeatureFlags(), - ).toEqual([]); - - /* deprecated tests */ - - expect( - createPlugin({ - id: 'test', - featureFlags: [{ name: 'test' }], - }).output(), - ).toEqual([{ name: 'test', type: 'feature-flag' }]); - - expect( - createPlugin({ - id: 'test', - register({ featureFlags }) { - featureFlags.register('blob'); - }, - }).output(), - ).toEqual([{ name: 'blob', type: 'feature-flag' }]); - expect( - createPlugin({ - id: 'test', - register({ featureFlags }) { - featureFlags.register('blob'); - }, - featureFlags: [{ name: 'test' }], - }).output(), - ).toEqual([ - { name: 'test', type: 'feature-flag' }, - { name: 'blob', type: 'feature-flag' }, - ]); - - expect( - createPlugin({ - id: 'test', - }).output(), ).toEqual([]); }); }); diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 0fb7574cd7..d97554b27b 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -16,7 +16,6 @@ import { PluginConfig, - PluginOutput, BackstagePlugin, Extension, AnyRoutes, @@ -33,8 +32,6 @@ export class PluginImpl< ExternalRoutes extends AnyExternalRoutes, > implements BackstagePlugin { - private storedOutput?: PluginOutput[]; - constructor(private readonly config: PluginConfig) {} getId(): string { @@ -46,11 +43,7 @@ export class PluginImpl< } getFeatureFlags(): Iterable { - const registeredFlags = this.output() - .filter(({ type }) => type === 'feature-flag') - .map(({ name }) => ({ name })); - - return registeredFlags; + return this.config.featureFlags?.slice() ?? []; } get routes(): Routes { @@ -61,34 +54,6 @@ export class PluginImpl< return this.config.externalRoutes ?? ({} as ExternalRoutes); } - output(): PluginOutput[] { - if (this.storedOutput) { - return this.storedOutput; - } - const outputs = new Array(); - this.storedOutput = outputs; - - if (this.config.featureFlags) { - for (const flag of this.config.featureFlags) { - outputs.push({ type: 'feature-flag', name: flag.name }); - } - } - - if (!this.config.register) { - return outputs; - } - - this.config.register({ - featureFlags: { - register(name) { - outputs.push({ type: 'feature-flag', name }); - }, - }, - }); - - return this.storedOutput; - } - provide(extension: Extension): T { return extension.expose(this); } diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 4f7609fd9c..95f5a6b219 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -20,10 +20,7 @@ export type { AnyRoutes, BackstagePlugin, Extension, - FeatureFlagOutput, FeatureFlagsHooks, PluginConfig, - PluginHooks, - PluginOutput, PluginFeatureFlagConfig, } from './types'; diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 0f8d3404d8..d639327838 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -17,24 +17,6 @@ import { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing'; import { AnyApiFactory } from '../apis/system'; -/** - * Replace with using {@link RouteRef}s. - * @deprecated will be removed - * @public - */ -export type FeatureFlagOutput = { - type: 'feature-flag'; - name: string; -}; - -/** - * {@link FeatureFlagOutput} type. - * - * @public - * @deprecated Use {@link BackstagePlugin.getFeatureFlags} instead. - */ -export type PluginOutput = FeatureFlagOutput; - /** * Plugin extension type. * @@ -72,10 +54,6 @@ export type BackstagePlugin< ExternalRoutes extends AnyExternalRoutes = {}, > = { getId(): string; - /** - * @deprecated use getFeatureFlags instead. - * */ - output(): PluginOutput[]; getApis(): Iterable; /** * Returns all registered feature flags for this plugin. @@ -107,23 +85,11 @@ export type PluginConfig< > = { id: string; apis?: Iterable; - /** @deprecated use featureFlags property instead for defining feature flags */ - register?(hooks: PluginHooks): void; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; }; -/** - * Holds hooks registered by the plugin. - * - * @deprecated - feature flags are now registered in plugin config under featureFlags - * @public - */ -export type PluginHooks = { - featureFlags: FeatureFlagsHooks; -}; - /** * Interface for registering feature flags hooks. * diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 9d71eadeb0..f72e76b9c0 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,127 @@ # @backstage/create-app +## 0.4.11 + +## 0.4.10 + +### Patch Changes + +- 79b342bd36: removed inline and internal CSS from index.html + + To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file: + + Remove internal style + + ```diff + - + ``` + + Remove inline style from the body tag + + ```diff + - + + + ``` + +- d33b65dc52: Removed unused templating asset. +- 613ad12960: Add a comment to the default backend about the fallback 404 handler. +- 20af5a701f: The `` filter in the composed `SearchPage.tsx` was replaced with the `` variant. + + This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout: + + ```diff + --- a/packages/app/src/components/search/SearchPage.tsx + +++ b/packages/app/src/components/search/SearchPage.tsx + @@ -11,7 +11,7 @@ import { + SearchType, + DefaultResultListItem, + } from '@backstage/plugin-search'; + -import { Content, Header, Page } from '@backstage/core-components'; + +import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components'; + + const useStyles = makeStyles((theme: Theme) => ({ + bar: { + @@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({ + }, + filters: { + padding: theme.spacing(2), + + marginTop: theme.spacing(2), + }, + filter: { + '& + &': { + @@ -41,12 +42,23 @@ const SearchPage = () => { + + + + + , + + }, + + { + + value: 'techdocs', + + name: 'Documentation', + + icon: , + + }, + + ]} + + /> + + - + { + // ... + + const scheduler = taskScheduler.forPlugin(plugin); + return { + + scheduler, + // ... + ``` + ## 0.4.9 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 3c4f403703..639e0370d7 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.9", + "version": "0.4.11", "private": false, "publishConfig": { "access": "public" @@ -49,6 +49,7 @@ }, "peerDependencies": { "@backstage/backend-common": "*", + "@backstage/backend-tasks": "*", "@backstage/catalog-client": "*", "@backstage/catalog-model": "*", "@backstage/cli": "*", @@ -66,6 +67,8 @@ "@backstage/plugin-explore": "*", "@backstage/plugin-github-actions": "*", "@backstage/plugin-lighthouse": "*", + "@backstage/plugin-permission-common": "*", + "@backstage/plugin-permission-node": "*", "@backstage/plugin-proxy-backend": "*", "@backstage/plugin-rollbar-backend": "*", "@backstage/plugin-scaffolder": "*", diff --git a/packages/create-app/src/lib/tasks.ts b/packages/create-app/src/lib/tasks.ts index 2793088892..4bd7050fc2 100644 --- a/packages/create-app/src/lib/tasks.ts +++ b/packages/create-app/src/lib/tasks.ts @@ -167,8 +167,8 @@ export async function checkAppExistsTask(rootDir: string, name: string) { /** * Verify that application `path` exists, otherwise create the directory * - * @param {string} path - target to create directory - * @throws {Error} if `path` is a file, or `fs.mkdir` fails + * @param path - target to create directory + * @throws if `path` is a file, or `fs.mkdir` fails */ export async function checkPathExistsTask(path: string) { await Task.forItem('checking', path, async () => { @@ -184,8 +184,8 @@ export async function checkPathExistsTask(path: string) { /** * Create a folder to store templated files * - * @param {string} tempDir - target temporary directory - * @throws {Error} if `fs.mkdir` fails + * @param tempDir - target temporary directory + * @throws if `fs.mkdir` fails */ export async function createTemporaryAppFolderTask(tempDir: string) { await Task.forItem('creating', 'temporary directory', async () => { @@ -200,7 +200,7 @@ export async function createTemporaryAppFolderTask(tempDir: string) { /** * Run `yarn install` and `run tsc` in application directory * - * @param {string} appDir - location of application to build + * @param appDir - location of application to build */ export async function buildAppTask(appDir: string) { const runCmd = async (cmd: string) => { @@ -221,10 +221,10 @@ export async function buildAppTask(appDir: string) { /** * Move temporary directory to destination application folder * - * @param {string} tempDir source path to copy files from - * @param {string} destination target path to copy files - * @param {string} id - * @throws {Error} if `fs.move` fails + * @param tempDir - source path to copy files from + * @param destination - target path to copy files + * @param id - item ID + * @throws if `fs.move` fails */ export async function moveAppTask( tempDir: string, diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 6c85652c64..f89ff7f391 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -32,6 +32,7 @@ leaving any imports in place. import { version as appDefaults } from '../../../app-defaults/package.json'; import { version as backendCommon } from '../../../backend-common/package.json'; +import { version as backendTasks } from '../../../backend-tasks/package.json'; import { version as catalogClient } from '../../../catalog-client/package.json'; import { version as catalogModel } from '../../../catalog-model/package.json'; import { version as cli } from '../../../cli/package.json'; @@ -56,6 +57,8 @@ import { version as pluginExplore } from '../../../../plugins/explore/package.js import { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json'; import { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json'; import { version as pluginOrg } from '../../../../plugins/org/package.json'; +import { version as pluginPermissionCommon } from '../../../../plugins/permission-common/package.json'; +import { version as pluginPermissionNode } from '../../../../plugins/permission-node/package.json'; import { version as pluginProxyBackend } from '../../../../plugins/proxy-backend/package.json'; import { version as pluginRollbarBackend } from '../../../../plugins/rollbar-backend/package.json'; import { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json'; @@ -71,6 +74,7 @@ import { version as pluginUserSettings } from '../../../../plugins/user-settings export const packageVersions = { '@backstage/app-defaults': appDefaults, '@backstage/backend-common': backendCommon, + '@backstage/backend-tasks': backendTasks, '@backstage/catalog-client': catalogClient, '@backstage/catalog-model': catalogModel, '@backstage/cli': cli, @@ -92,6 +96,8 @@ export const packageVersions = { '@backstage/plugin-github-actions': pluginGithubActions, '@backstage/plugin-lighthouse': pluginLighthouse, '@backstage/plugin-org': pluginOrg, + '@backstage/plugin-permission-common': pluginPermissionCommon, + '@backstage/plugin-permission-node': pluginPermissionNode, '@backstage/plugin-proxy-backend': pluginProxyBackend, '@backstage/plugin-rollbar-backend': pluginRollbarBackend, '@backstage/plugin-scaffolder': pluginScaffolder, diff --git a/packages/create-app/templates/default-app/packages/app/public/index.html b/packages/create-app/templates/default-app/packages/app/public/index.html index 1bd6001a51..a936c73602 100644 --- a/packages/create-app/templates/default-app/packages/app/public/index.html +++ b/packages/create-app/templates/default-app/packages/app/public/index.html @@ -42,11 +42,6 @@ href="<%= publicPath %>/safari-pinned-tab.svg" color="#5bbad5" /> - <%= config.getString('app.title') %> <% if (config.has('app.googleAnalyticsTrackingId')) { %>