diff --git a/.changeset/angry-ghosts-report.md b/.changeset/angry-ghosts-report.md deleted file mode 100644 index dfa83663a9..0000000000 --- a/.changeset/angry-ghosts-report.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Support a `ensureExists` config option to skip ensuring a configured database exists. This allows deployment scenarios where -limited permissions are given for provisioned databases without privileges to create new databases. If set to `false`, the -database connection will not be validated prior to use which means the backend will not attempt to create the database if it -doesn't exist. You can configure this in your app-config.yaml: - -```yaml -backend: - database: - ensureExists: false -``` - -This defaults to `true` if unspecified. You can also configure this per plugin connection and will override the base option. diff --git a/.changeset/angry-rules-fail.md b/.changeset/angry-rules-fail.md deleted file mode 100644 index cc52d4478e..0000000000 --- a/.changeset/angry-rules-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Add unstable prop for disabling unregister entity menu diff --git a/.changeset/chilled-schools-raise.md b/.changeset/chilled-schools-raise.md new file mode 100644 index 0000000000..56058b6125 --- /dev/null +++ b/.changeset/chilled-schools-raise.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Make sure that the unique databases names generated by `TestDatabases.create()` +don't collide. diff --git a/.changeset/curly-badgers-sit.md b/.changeset/curly-badgers-sit.md deleted file mode 100644 index ca740e907a..0000000000 --- a/.changeset/curly-badgers-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Store filter values set in `EntityListProvider` in query parameters. This allows selected filters to be restored when returning to pages that list catalog entities. diff --git a/.changeset/eighty-glasses-mate.md b/.changeset/eighty-glasses-mate.md new file mode 100644 index 0000000000..d71ef8fd42 --- /dev/null +++ b/.changeset/eighty-glasses-mate.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Use a more informative error message when URL reading isn't allowed due to no reader matching the target URL. diff --git a/.changeset/green-vans-peel.md b/.changeset/green-vans-peel.md deleted file mode 100644 index cd4d30139a..0000000000 --- a/.changeset/green-vans-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Fix `EntityTypeFilter` so it produces unique case-insensitive set of available types diff --git a/.changeset/grumpy-dolls-call.md b/.changeset/grumpy-dolls-call.md deleted file mode 100644 index 13d96ecb1f..0000000000 --- a/.changeset/grumpy-dolls-call.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/plugin-catalog-react': minor -'@backstage/plugin-scaffolder': patch ---- - -Updated the software templates list page (`ScaffolderPage`) to use the `useEntityListProvider` hook from #5643. This reduces the code footprint, making it easier to customize the display of this page, and consolidates duplicate approaches to querying the catalog with filters. - -- The `useEntityTypeFilter` hook has been updated along with the underlying `EntityTypeFilter` to work with multiple values, to allow more flexibility for different user interfaces. It's unlikely that this change affects you; however, if you're using either of these directly, you'll need to update your usage. -- `SearchToolbar` was renamed to `EntitySearchBar` and moved to `catalog-react` to be usable by other entity list pages -- `UserListPicker` now has an `availableTypes` prop to restrict which user-related options to present diff --git a/.changeset/lemon-crabs-confess.md b/.changeset/lemon-crabs-confess.md deleted file mode 100644 index 0d87843df5..0000000000 --- a/.changeset/lemon-crabs-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Updating fs-extra to 10.0.0 to handle broken symbolic links correctly diff --git a/.changeset/lemon-dancers-taste.md b/.changeset/lemon-dancers-taste.md deleted file mode 100644 index 0542fe4a54..0000000000 --- a/.changeset/lemon-dancers-taste.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -The codeowners processor extracts the username of the primary owner and uses this as the owner field. -Given the kind isn't specified this is assumed to be a group and so the link to the owner in the about card -doesn't work. This change specifies the kind where the entity is a user. e.g: - -`@iain-b` -> `user:iain-b` diff --git a/.changeset/modern-ghosts-dress.md b/.changeset/modern-ghosts-dress.md new file mode 100644 index 0000000000..6d3cdbfd3c --- /dev/null +++ b/.changeset/modern-ghosts-dress.md @@ -0,0 +1,25 @@ +--- +'@backstage/core-app-api': patch +'@backstage/core-components': patch +'@backstage/core-plugin-api': patch +'@backstage/dev-utils': patch +'@backstage/test-utils': patch +'@backstage/test-utils-core': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-git-release-manager': patch +'@backstage/plugin-lighthouse': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-rollbar': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-search': patch +'@backstage/plugin-sentry': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-techdocs': patch +--- + +Switched `@types/react` dependency to request `*` rather than a specific version. diff --git a/.changeset/nice-bugs-beg.md b/.changeset/nice-bugs-beg.md deleted file mode 100644 index c41b54b220..0000000000 --- a/.changeset/nice-bugs-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': minor ---- - -Exported and renamed components from the `@backstage/plugin-user-settings` plugin , to be able to use it in the consumer side and customize the `SettingPage` diff --git a/.changeset/polite-spies-judge.md b/.changeset/polite-spies-judge.md deleted file mode 100644 index 075bcf1598..0000000000 --- a/.changeset/polite-spies-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-rails': patch ---- - -updated paths to consider differences between platform (windows corrected) diff --git a/.changeset/poor-otters-buy.md b/.changeset/poor-otters-buy.md deleted file mode 100644 index b60cbddc1b..0000000000 --- a/.changeset/poor-otters-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add new `fetch:template` action which handles the same responsibilities as `fetch:cookiecutter` without the external dependency on `cookiecutter`. For information on migrating from `fetch:cookiecutter` to `fetch:template`, see the [migration guide](https://backstage.io/docs/features/software-templates/builtin-actions#migrating-from-fetch-cookiecutter-to-fetch-template) in the docs. diff --git a/.changeset/pretty-drinks-serve.md b/.changeset/pretty-drinks-serve.md deleted file mode 100644 index a012aba11f..0000000000 --- a/.changeset/pretty-drinks-serve.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Scaffolder: Added an 'eq' handlebars helper for use in software template YAML files. This can be used to execute a step depending on the value of an input, e.g.: - -```yaml -steps: - id: 'conditional-step' - action: 'custom-action' - if: '{{ eq parameters.myvalue "custom" }}', -``` diff --git a/.changeset/real-plums-vanish.md b/.changeset/real-plums-vanish.md deleted file mode 100644 index a653a6bdf2..0000000000 --- a/.changeset/real-plums-vanish.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Add Sign In and Handler resolver for Microsoft provider diff --git a/.changeset/search-early-horses-sip.md b/.changeset/search-early-horses-sip.md new file mode 100644 index 0000000000..ce5612ae86 --- /dev/null +++ b/.changeset/search-early-horses-sip.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-backend-module-pg': patch +--- + +Add `plugin-search-backend-module-pg` providing a postgres based search engine. +See the [README of `search-backend-module-pg`](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-pg/README.md) for usage instructions. diff --git a/.changeset/search-mighty-mice-collect.md b/.changeset/search-mighty-mice-collect.md deleted file mode 100644 index bad91ff853..0000000000 --- a/.changeset/search-mighty-mice-collect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-search-backend-node': minor ---- - -Change return value of `SearchEngine.index` to `Promise` to support -implementation of external search engines. diff --git a/.changeset/sharp-berries-fail.md b/.changeset/sharp-berries-fail.md new file mode 100644 index 0000000000..a713b3fdee --- /dev/null +++ b/.changeset/sharp-berries-fail.md @@ -0,0 +1,34 @@ +--- +'@backstage/create-app': patch +--- + +Add a complete prettier setup to the created project. Prettier used to only be added as a dependency to create apps, but there wasn't a complete setup included that makes it easy to run prettier. That has now changed, and the new `prettier:check` command can be used to check the formatting of the files in your created project. + +To apply this change to an existing app, a couple of changes need to be made. + +Create a `.prettierignore` file at the root of your repository with the following contents: + +``` +dist +dist-types +coverage +.vscode +``` + +Next update the root `package.json` by bumping the prettier version and adding the new `prettier:check` command: + +```diff + "scripts": { + ... ++ "prettier:check": "prettier --check .", + ... + }, + ... + "dependencies": { + ... +- "prettier": "^1.19.1" ++ "prettier": "^2.3.2" + } +``` + +Finally run `yarn prettier --write .` on your project to update the existing formatting. diff --git a/.changeset/short-eggs-confess.md b/.changeset/short-eggs-confess.md deleted file mode 100644 index 3fa240a347..0000000000 --- a/.changeset/short-eggs-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch ---- - -Expose missing types used by the custom transformers diff --git a/.changeset/shy-rules-design.md b/.changeset/shy-rules-design.md deleted file mode 100644 index 4f009e5aa8..0000000000 --- a/.changeset/shy-rules-design.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Updated inputs for the `publish:github:pull-request` action. - -Now requires a `repoUrl` instead of separate `owner` and `repo` inputs. This aligns with the output of the `RepoUrlPicker` ui field used by the pull-request sample template. diff --git a/.changeset/small-actors-sing.md b/.changeset/small-actors-sing.md new file mode 100644 index 0000000000..40de0f363f --- /dev/null +++ b/.changeset/small-actors-sing.md @@ -0,0 +1,12 @@ +--- +'@backstage/create-app': patch +--- + +Switched `@types/react-dom` dependency to of the app package to request `*` rather than a specific version. + +To apply this change to an existing app, change the following in `packages/app/package.json`: + +```diff +- "@types/react-dom": "^16.9.8", ++ "@types/react-dom": "*", +``` diff --git a/.changeset/small-guests-invite.md b/.changeset/small-guests-invite.md new file mode 100644 index 0000000000..507e0b3d12 --- /dev/null +++ b/.changeset/small-guests-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Support deep linking in OpenAPI definitions. diff --git a/.changeset/techdocs-typescript-isnt-fun.md b/.changeset/techdocs-typescript-isnt-fun.md deleted file mode 100644 index 9341c1c14a..0000000000 --- a/.changeset/techdocs-typescript-isnt-fun.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch ---- - -It is no longer required to provide a generator and a preparer to the TechDocs -router factory when running TechDocs in the "recommended" (e.g. externally -prepared and generated docs) configuration. diff --git a/.changeset/wise-rockets-smoke.md b/.changeset/wise-rockets-smoke.md deleted file mode 100644 index c81d20519d..0000000000 --- a/.changeset/wise-rockets-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Document the default behavior of `statusCheck` option in `createStatusCheckRouter`. diff --git a/.changeset/young-tables-reply.md b/.changeset/young-tables-reply.md deleted file mode 100644 index e08a875c14..0000000000 --- a/.changeset/young-tables-reply.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/cli': patch -'@backstage/config-loader': patch -'@backstage/create-app': patch -'@backstage/techdocs-common': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-rollbar-backend': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-techdocs-backend': patch ---- - -Revert the upgrade to `fs-extra@10.0.0` as that seemed to have broken all installs inexplicably. diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index e6af881f1e..6f28680ecb 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -1,5 +1,6 @@ abc accessors +Anddddd Apdex api Api @@ -74,6 +75,7 @@ dockerode Docusaurus env Env +elasticsearch esbuild eslint etag @@ -212,6 +214,7 @@ repos rerender Reusability reusability +roadmaps rollbar Rollbar Rollup @@ -220,6 +223,7 @@ Routable rst rsync ruleset +runbook sam sanitization scaffolded diff --git a/.github/workflows/e2e-win.yml b/.github/workflows/e2e-win.yml index 1844700cea..3e2fbe0863 100644 --- a/.github/workflows/e2e-win.yml +++ b/.github/workflows/e2e-win.yml @@ -25,6 +25,13 @@ jobs: name: Node ${{ matrix.node-version }} on ${{ matrix.os }} steps: + # In order to have the create-app template function as if it was downloaded from NPM + # we need to make sure we checkout files with LF line endings only + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + - uses: actions/checkout@v2 - name: use node.js ${{ matrix.node-version }} diff --git a/ADOPTERS.md b/ADOPTERS.md index 1dcd4a774f..72b6cce072 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -1,39 +1,44 @@ -| Organization | Contact | Description of Use | -| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. | -| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. | -| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. | -| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up | -| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. | -| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. | -| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. | -| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications | -| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. | -| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | -| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D | -| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling | -| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling | -| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks | -| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. | -| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. | -| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. | -| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo), [Erik Lindgren](https://github.com/lindgren) | EG Common Developer Toolkit | -| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go | -| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling | -| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. | -| [Trendyol](https://trendyol.com) | [Erdogan Oksuz](https://github.com/erdoganoksuz) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. | -| [Peloton](https://www.onepeloton.com/) | [Jim Haughwout](https://github.com/JimHaughwout) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. | -| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. | -| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a team’s engineering dependencies. | -| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. | -| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. | -| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. | -| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. | -| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. | -| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 | -| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes | -| [DAZN](https://dazn.com/) | [Lou Bichard](https://twitter.com/loujaybee), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). | -| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. | -| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. | -| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | -| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. | +| Organization | Contact | Description of Use | +| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. | +| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. | +| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. | +| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up | +| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. | +| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. | +| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. | +| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications | +| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. | +| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | +| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D | +| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling | +| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling | +| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks | +| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. | +| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. | +| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. | +| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo), [Erik Lindgren](https://github.com/lindgren) | EG Common Developer Toolkit | +| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go | +| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling | +| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. | +| [Trendyol](https://trendyol.com) | [Erdogan Oksuz](https://github.com/erdoganoksuz) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. | +| [Peloton](https://www.onepeloton.com/) | [Jim Haughwout](https://github.com/JimHaughwout) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. | +| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. | +| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a team’s engineering dependencies. | +| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. | +| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. | +| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. | +| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. | +| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. | +| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 | +| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes | +| [DAZN](https://dazn.com/) | [Lou Bichard](https://twitter.com/loujaybee), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). | +| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. | +| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. | +| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | +| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. | +| [MavTek](https://www.mavtek.com/) | [@fgascon](https://github.com/fgascon) | Developer portal focused on standardizing practices, centralizing documentation and streamlining developer practices. | +| [QuintoAndar](https://www.quintoandar.com.br/) | [@quintoandar](https://github.com/quintoandar) | Developer portal, services catalog and centralization of service metrics. | +| [empathy.co](https://empathy.co/) | [@guillermotti](https://github.com/guillermotti) | Developer portal for tech docs, service catalog, plugin discovery and much more. | +| [creditas.com](https://creditas.com/) | [@aureliosaraiva](https://github.com/aureliosaraiva) [@Creditas](https://github.com/creditas) | Centralization of all services, standards, documentation, etc. We started the deployment process. | +| [Prisjakt](https://www.prisjakt.nu) / [PriceSpy](https://pricespy.co.uk) | [@kennylindahl](https://github.com/kennylindahl) | Internal developer portal - Documentation, scaffolding, software catalog, TechRadar, Gitlab org data integration | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2caa8c9c9c..466c77c575 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ In general, changesets are not needed for the documentation, build utilities, co 1. Run `yarn changeset` 2. Select which packages you want to include a changeset for -3. Select impact of change that you're introducing (patch, minor, or major) +3. Select impact of change that you're introducing, using `minor` for breaking changes and `patch` otherwise. We do not use `major` changes while packages are at version `0.x`. 4. Add generated changeset to Git 5. Push the commit with your changeset to the branch associated with your PR 6. Accept our gratitude for making the release process easier on the maintainers diff --git a/README.md b/README.md index 98da194c1b..7dc548c53f 100644 --- a/README.md +++ b/README.md @@ -63,3 +63,9 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how Copyright 2020-2021 © The Backstage Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + +## Security + +Please report sensitive security issues via Spotify's [bug-bounty program](https://hackerone.com/spotify) rather than GitHub. + +For further details please see our complete [security release process](SECURITY.md). diff --git a/SECURITY.md b/SECURITY.md index 3ec51b4210..b410404bcf 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,3 +9,20 @@ ## Reporting a Vulnerability Please report sensitive security issues via Spotify's [bug-bounty program](https://hackerone.com/spotify) rather than GitHub. + +If you have questions about a potential vulnerability, please reach out on Discord by asking for a maintainer in the `#support` channel, or via direct message to a maintainer. + +## Remediation and Notification Process + +Vulnerabilities are handled and published through [GitHub Security Advisories](https://docs.github.com/en/code-security/security-advisories/about-github-security-advisories). + +In the event of a vulnerability the runbook for the maintainers is as follows: + +1. Create a [new draft security advisory](https://github.com/backstage/backstage/security/advisories/new). The values and descriptions don't need to be perfect to begin with as they can be edited later. For severity, use the "Assess severity using CVSS" and refer to [the guide](https://www.first.org/cvss/v3.1/user-guide) for help. +2. Request a CVE identification number. It can take up to 72h for one to be assigned so be sure to do this early on. +3. If there is not already a patch for the vulnerability, collaborate on one in a private fork: + 1. Head to the security advisory on GitHub and [create a private fork](https://docs.github.com/en/code-security/security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerability) + 1. [Invite any collaborators](https://docs.github.com/en/code-security/security-advisories/adding-a-collaborator-to-a-security-advisory) from outside the maintainer team that should be part of creating a fix. + 1. Create one or multiple Pull Requests with fixes towards the fork. Note that these PRs will not have CI checks run on them, so more care should be taken to run local validation. The PRs are also not merged like normal PRs, but are instead merged straight into the main repo all at once when the merge button is hit on the security advisory. +4. Once the fix is ready in a PR or private fork and it is time to release it, there are a couple of options. Either merge into the main branch with a changeset and wait for a regular release, or do a quick release by manually bumping the version in `package.json` of the affected package, along with a manual `CHANGELOG.md` entry. Note that a quick release will only work if the package does not have any other pending changes that depend on pending changes in other packages, so be sure to manually check that first, and fall back to an early regular release if needed. In general it's best to stick with the regular release flow, with the quick release being used only for time sensitive fixes. +5. Finalize and publish the security advisory. Note that once you hit the publish button it's no longer possible to edit the advisory. Just like the CVE number this can take up to 72h, and expect it to be slower than the CVE number request. diff --git a/app-config.yaml b/app-config.yaml index b50de963ed..f2df97b7b2 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -101,8 +101,10 @@ organization: # 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: - techdocs: 'docker' # Alternatives - 'local' + generator: + runIn: 'docker' + # dockerImage: my-org/techdocs # use a custom docker image + # pullImage: true # or false to disable automatic pulling of image (e.g. if custom docker login is required) publisher: type: 'local' # Alternatives - 'googleGcs' or 'awsS3' or 'azureBlobStorage' or 'openStackSwift'. Read documentation for using alternatives. @@ -254,6 +256,8 @@ scaffolder: # defaultAuthor: # name: Scaffolder # email: scaffolder@backstage.io + # Use to customize the default commit message when new components are created + # defaultCommitMessage: 'Initial commit' github: token: ${GITHUB_TOKEN} visibility: public # or 'internal' or 'private' @@ -312,13 +316,20 @@ auth: # # scope: saml-login-selector openid profile email oidc: + # Note that you must define a session secret (see above) since the oidc provider requires session support. + # Note that by default, this provider will use the 'none' prompt which assumes that your are already logged on in the IDP. + # You should set prompt to: + # - auto: will let the IDP decide if you need to log on or if you can skip login when you have an active SSO session + # - login: will force the IDP to always present a login form to the user development: metadataUrl: ${AUTH_OIDC_METADATA_URL} clientId: ${AUTH_OIDC_CLIENT_ID} clientSecret: ${AUTH_OIDC_CLIENT_SECRET} authorizationUrl: ${AUTH_OIDC_AUTH_URL} tokenUrl: ${AUTH_OIDC_TOKEN_URL} - tokenSignedResponseAlg: ${AUTH_OIDC_TOKEN_SIGNED_RESPONSE_ALG} + tokenSignedResponseAlg: ${AUTH_OIDC_TOKEN_SIGNED_RESPONSE_ALG} # default='RS256' + scope: ${AUTH_OIDC_SCOPE} # default='openid profile email' + prompt: ${AUTH_OIDC_PROMPT} # default=none (allowed values: auto, none, consent, login) auth0: development: clientId: ${AUTH_AUTH0_CLIENT_ID} @@ -370,3 +381,9 @@ homepage: timezone: 'Asia/Tokyo' pagerduty: eventsBaseUrl: 'https://events.pagerduty.com/v2' +jenkins: + instances: + - name: default + baseUrl: https://jenkins.example.com + username: backstage-bot + apiKey: 123456789abcdef0123456789abcedf012 diff --git a/catalog-info.yaml b/catalog-info.yaml index 0cab0c558a..6de6fd3426 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -15,7 +15,7 @@ metadata: url: https://discord.com/invite/EBHEGzX annotations: github.com/project-slug: backstage/backstage - backstage.io/techdocs-ref: url:https://github.com/backstage/backstage + backstage.io/techdocs-ref: dir:. lighthouse.com/website-url: https://backstage.io spec: type: library diff --git a/contrib/docs/tutorials/aws-deployment.md b/contrib/docs/tutorials/aws-deployment.md index 47170658a3..3a76da2ed3 100644 --- a/contrib/docs/tutorials/aws-deployment.md +++ b/contrib/docs/tutorials/aws-deployment.md @@ -5,7 +5,7 @@ image](https://backstage.io/docs/getting-started/deployment-docker); this tutorial shows how to deploy that Docker image to AWS using Elastic Container Registry (ECR) and Elastic Kubernetes Service (EKS). Amazon also supports deployments with Helm, covered in the [Helm -Kubernetes](../kubernetes/basic_kubernetes_example_with_helm) example. +Kubernetes](../../kubernetes/basic_kubernetes_example_with_helm) example. The basic workflow for this method is to build a Backstage Docker image, upload the new version to a container registry, and update a Kubernetes deployment with diff --git a/docs/features/search/architecture.md b/docs/features/search/architecture.md index 0a1ebea4b0..4fac0e7cff 100644 --- a/docs/features/search/architecture.md +++ b/docs/features/search/architecture.md @@ -4,8 +4,6 @@ title: Search Architecture description: Documentation on Search Architecture --- -# Search Architecture - > _This architecture has not been fully implemented yet. Find our milestones to > follow our progress and help contribute on the > [Search Roadmap](./README.md#project-roadmap)._ diff --git a/docs/features/search/concepts.md b/docs/features/search/concepts.md index 5da7c9c58f..8cb17b12e6 100644 --- a/docs/features/search/concepts.md +++ b/docs/features/search/concepts.md @@ -4,8 +4,6 @@ title: Search Concepts description: Documentation on Backstage Search Concepts --- -# Search Concepts - Backstage Search lets you find the right information you are looking for in the Backstage ecosystem. diff --git a/docs/features/search/getting-started.md b/docs/features/search/getting-started.md index 2bd26faf8b..aa40c1e539 100644 --- a/docs/features/search/getting-started.md +++ b/docs/features/search/getting-started.md @@ -4,8 +4,6 @@ title: Getting Started with Search description: How to set up and install Backstage Search --- -# Getting Started - Search functions as a plugin to Backstage, so you will need to use Backstage to use Search. @@ -252,13 +250,9 @@ an example: Backstage Search isn't a search engine itself, rather, it provides an interface between your Backstage instance and a [Search Engine](./concepts.md#search-engines) of your choice. Currently, we only -support one, an in-memory search Engine called Lunr. It can be instantiated like -this: - -```typescript -const searchEngine = new LunrSearchEngine({ logger }); -const indexBuilder = new IndexBuilder({ logger, searchEngine }); -``` +support two engines, an in-memory search Engine called Lunr and ElasticSearch. +See [Search Engines](./search-engines.md) documentation for more information how +to configure these in your Backstage instance. Backstage Search can be used to power search of anything! Plugins like the Catalog offer default [collators](./concepts.md#collators) (e.g. diff --git a/docs/features/search/search-engines.md b/docs/features/search/search-engines.md new file mode 100644 index 0000000000..a2e4831824 --- /dev/null +++ b/docs/features/search/search-engines.md @@ -0,0 +1,171 @@ +--- +id: search-engines +title: Search Engines +description: Choosing and configuring your search engine for Backstage +--- + +Backstage supports 2 search engines by default, an in-memory engine called Lunr +and ElasticSearch. You can configure your own search engines by implementing the +provided interface as mentioned in the +[search backend documentation.](./getting-started.md#Backend) + +Provided search engine implementations have their own way of constructing +queries, which may be something you want to modify. Alterations to the querying +logic of a search engine can be made by providing your own implementation of a +QueryTranslator interface. This modification can be done without touching +provided search engines by using the exposed setter to set the modified query +translator into the instance. + +```typescript +const searchEngine = new LunrSearchEngine({ logger }); +searchEngine.setTranslator(new MyNewAndBetterQueryTranslator()); +``` + +## Lunr + +Lunr search engine is enabled by default for your backstage instance if you have +not done additional changes to the scaffolded app. + +Lunr can be instantiated like this: + +```typescript +// app/backend/src/plugins/search.ts +const searchEngine = new LunrSearchEngine({ logger }); +const indexBuilder = new IndexBuilder({ logger, searchEngine }); +``` + +## Postgres + +The Postgres based search engine only requires that postgres being configured as +the database engine for Backstage. Therefore it targets setups that want to +avoid maintaining another external service like elastic search. The search +provides decent results and performs well with ten thousands of indexed +documents. The connection to postgres is established via the database manager +also used by other plugins. + +> **Important**: The search plugin requires at least Postgres 11! + +To use the `PgSearchEngine`, make sure that you have a Postgres database +configured and make the following changes to your backend: + +1. Add a dependency on `@backstage/plugin-search-backend-module-pg` to your + backend's `package.json`. +2. Initialize the search engine. It is recommended to initialize it with a + fallback to the lunr search engine if you are running Backstage for + development locally with SQLite: + +```typescript +// In packages/backend/src/plugins/search.ts + +// Initialize a connection to a search engine. +const searchEngine = (await PgSearchEngine.supported(database)) + ? await PgSearchEngine.from({ database }) + : new LunrSearchEngine({ logger }); +``` + +## ElasticSearch + +Backstage supports ElasticSearch search engine connections, indexing and +querying out of the box. Available configuration options enable usage of either +AWS or Elastic.co hosted solutions, or a custom self-hosted solution. + +Similarly to Lunr above, ElasticSearch can be set up like this: + +```typescript +// app/backend/src/plugins/search.ts +const searchEngine = await ElasticSearchSearchEngine.initialize({ + logger, + config, +}); +const indexBuilder = new IndexBuilder({ logger, searchEngine }); +``` + +For the engine to be available, your backend package needs a dependency into +package `@backstage/plugin-search-backend-module-elasticsearch`. + +ElasticSearch needs some additional configuration before it is ready to use +within your instance. The configuration options are documented in the +[configuration schema definition file.](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-elasticsearch/config.d.ts) + +The underlying functionality is using official ElasticSearch client version 7.x, +meaning that ElasticSearch version 7 is the only one confirmed to be supported. + +## Example configurations + +### AWS + +Using AWS hosted ElasticSearch the only configuration option needed is the URL +to the ElasticSearch service. The implementation assumes that environment +variables for AWS access key id and secret access key are defined in accordance +to the +[default AWS credential chain.](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html). + +```yaml +search: + elasticsearch: + provider: aws + node: https://my-backstage-search-asdfqwerty.eu-west-1.es.amazonaws.com +``` + +### Elastic.co + +Elastic Cloud hosted ElasticSearch uses a Cloud ID to determine the instance of +hosted ElasticSearch to connect to. Additionally, username and password needs to +be provided either directly or using environment variables like defined in +[Backstage documentation.](https://backstage.io/docs/conf/writing#includes-and-dynamic-data) + +```yaml +search: + elasticsearch: + provider: elastic + cloudId: backstage-elastic:asdfqwertyasdfqwertyasdfqwertyasdfqwerty== + auth: + username: elastic + password: changeme +``` + +### Others + +Other ElasticSearch instances can be connected to by using standard +ElasticSearch authentication methods and exposed URL, provided that the cluster +supports that. The configuration options needed are the URL to the node and +authentication information. Authentication can be handled by either providing +username/password or an API key or a bearer token. In case both +username/password combination and one of the tokens are provided, token takes +precedence. For more information how to create an API key, see +[Elastic documentation on API keys](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html), +and how to create a bearer token see +[Elastic documentation on tokens.](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-service-token.html) + +#### Configuration examples + +##### With username and password + +```yaml +search: + elasticsearch: + node: http://localhost:9200 + auth: + username: elastic + password: changeme +``` + +##### With bearer token + +```yaml +search: + elasticsearch: + node: http://localhost:9200 + auth: + bearer: token +``` + +##### With API key + +```yaml +search: + elasticsearch: + node: http://localhost:9200 + auth: + apiKey: base64EncodedKey +``` diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md index e0228bf7d0..8d209cc8f0 100644 --- a/docs/features/software-catalog/catalog-customization.md +++ b/docs/features/software-catalog/catalog-customization.md @@ -27,27 +27,33 @@ default catalog page and create a component in a ```tsx // imports, etc omitted for brevity. for full source see: // https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx -export const CustomCatalogPage = () => { +export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', +}: CatalogPageProps) => { return ( - + - + All your software catalog entities -
- -
+ + +
- -
-
+ + + + + +
-
+ ); }; ``` @@ -137,19 +143,27 @@ export const EntitySecurityTierPicker = () => { Now we can add the component to `CustomCatalogPage`: ```diff -export const CustomCatalogPage = () => { +export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', +}: CatalogPageProps) => { return ( ... - -
+ + +
- -
+ + + + + + ... }; ``` diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md index a502c2aee5..f5296f38e1 100644 --- a/docs/features/software-catalog/index.md +++ b/docs/features/software-catalog/index.md @@ -8,12 +8,11 @@ description: The Backstage Software Catalog ## What is a Software Catalog? -The Backstage Software Catalog — actually, a software catalog, since it includes -more than just services — is a centralized system that keeps track of ownership -and metadata for all the software in your ecosystem (services, websites, -libraries, data pipelines, etc). The catalog is built around the concept of -[metadata YAML files](descriptor-format.md) stored together with the code, which -are then harvested and visualized in Backstage. +The Backstage Software Catalog is a centralized system that keeps track of +ownership and metadata for all the software in your ecosystem (services, +websites, libraries, data pipelines, etc). The catalog is built around the +concept of [metadata YAML files](descriptor-format.md) stored together with the +code, which are then harvested and visualized in Backstage. ![software-catalog](https://backstage.io/blog/assets/6/header.png) diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 67b92bd941..c0c347ac17 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -63,12 +63,18 @@ the `app-config.yaml` of a Backstage installation. # Example: metadata: annotations: - backstage.io/techdocs-ref: url:https://github.com/backstage/backstage/tree/master + backstage.io/techdocs-ref: dir:. ``` -The value of this annotation is a location reference string (see above). If this -annotation is specified, it is expected to point to a repository that the -TechDocs system can read and generate docs from. +The value of this annotation informs _where_ TechDocs source content is stored +so that it can be read and docs can be generated from it. Most commonly, it's +written as a path, relative to the location of the `catalog-info.yaml` itself, +where the associated `mkdocs.yml` file can be found. + +In unusual situations where the documentation for a catalog entity does not live +alongside the entity's source code, the value of this annotation can point to an +absolute URL, matching the location reference string format outlined above, for +example: `url:https://github.com/backstage/backstage/tree/master` ### backstage.io/view-url, backstage.io/edit-url @@ -101,18 +107,22 @@ repository itself. If the URL points to a folder, it is important that it is suffixed with a `'/'` in order for relative path resolution to work consistently. -### jenkins.io/github-folder +### jenkins.io/job-full-name ```yaml # Example: metadata: annotations: - jenkins.io/github-folder: folder-name/job-name + jenkins.io/job-full-name: folder-name/job-name ``` The value of this annotation is the path to a job on Jenkins, that builds this entity. +The value can be the format of just `[folder-path]` or +`[instanceName]:[folder-path]`, if multiple instances are configured in +`app-config.yaml` + Specifying this annotation may enable Jenkins related features in Backstage for that entity. @@ -304,6 +314,10 @@ This annotation allowed to load the API definition from another location. Use [substitution](./descriptor-format.md#substitutions-in-the-descriptor-format) instead. +### jenkins.io/github-folder + +Use the `jenkins.io/job-full-name` instead. + ## Links - [Descriptor Format: annotations](descriptor-format.md#annotations-optional) diff --git a/docs/features/software-templates/configuration.md b/docs/features/software-templates/configuration.md index cdd8166889..737f77f67b 100644 --- a/docs/features/software-templates/configuration.md +++ b/docs/features/software-templates/configuration.md @@ -33,9 +33,12 @@ scaffolder: ### Disabling Docker in Docker situation (Optional) -Software Templates use -[Cookiecutter](https://github.com/cookiecutter/cookiecutter) as a templating -library. By default it will use the +Software templates use the `fetch:template` action by default, which requires no +external dependencies and offers a +[Cookiecutter-compatible mode](https://backstage.io/docs/features/software-templates/builtin-actions#using-cookiecuttercompat-mode). +There is also a `fetch:cookiecutter` action, which uses +[Cookiecutter](https://github.com/cookiecutter/cookiecutter) directly for +templating. By default, the `fetch:cookiecutter` action will use the [scaffolder-backend/Cookiecutter](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile) docker image. diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 7b475f2fa1..02bb698f64 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -227,6 +227,33 @@ spec: inputType: tel ``` +#### Hide or mask sensitive data on Review step + +Sometimes, specially in custom fields, you collect some data on Create form that +must not be shown to the user on Review step. To hide or mask this data, you can +use `ui:widget: password` or set some properties of `ui:backstage`: + +```yaml +- title: Hide or mask values + properties: + password: + title: Password + type: string + ui:widget: password # will print '******' as value for property 'password' on Review Step + masked: + title: Masked + type: string + ui:backstage: + review: + mask: '' # will print '' as value for property 'Masked' on Review Step + hidden: + title: Hidden + type: string + ui:backstage: + review: + show: false # wont print any info about 'hidden' property on Review Step +``` + #### The Repository Picker So in order to make working with repository providers easier, we've built a diff --git a/docs/features/techdocs/configuration.md b/docs/features/techdocs/configuration.md index aa38dd42b1..4bb6857106 100644 --- a/docs/features/techdocs/configuration.md +++ b/docs/features/techdocs/configuration.md @@ -13,14 +13,29 @@ configuration options for TechDocs. # File: app-config.yaml techdocs: - # generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to - # spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of). - # You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running - # into Docker in Docker situation. Read more here - # https://backstage.io/docs/features/techdocs/getting-started#disable-docker-in-docker-situation-optional + # techdocs.generator is used to configure how documentation sites are generated using MkDocs. - generators: - techdocs: 'docker' + generator: + # techdocs.generator.runIn can be either 'docker' or 'local'. This is to determine how to run the generator - whether to + # spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of). + # You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running + # into Docker in Docker situation. Read more here + # https://backstage.io/docs/features/techdocs/getting-started#disable-docker-in-docker-situation-optional + + runIn: 'docker' + + # (Optional) techdocs.generator.dockerImage can be used to control the docker image used during documentation generation. This can be useful + # if you want to use MkDocs plugins or other packages that are not included in the default techdocs-container (spotify/techdocs). + # NOTE: This setting is only used when techdocs.generator.runIn is set to 'docker'. + + dockerImage: 'spotify/techdocs' + + # (Optional) techdocs.generator.pullImage can be used to disable pulling the latest docker image by default. This can be useful when you are + # using a custom techdocs.generator.dockerImage and you have a custom docker login requirement. For example, you need to login to + # AWS ECR to pull the docker image. + # NOTE: Disabling this requires the docker image was pulled by other means before running the techdocs generator. + + pullImage: true # techdocs.builder can be either 'local' or 'external. # If builder is set to 'local' and you open a TechDocs page, techdocs-backend will try to generate the docs, publish to storage diff --git a/docs/features/techdocs/creating-and-publishing.md b/docs/features/techdocs/creating-and-publishing.md index 3fdc942ac4..93ce3ad4d9 100644 --- a/docs/features/techdocs/creating-and-publishing.md +++ b/docs/features/techdocs/creating-and-publishing.md @@ -66,9 +66,7 @@ Update your component's entity description by adding the following lines to its ```yaml metadata: annotations: - backstage.io/techdocs-ref: url:https://github.com/org/repo - # Or - # backstage.io/techdocs-ref: url:https://github.com/org/repo/tree/branchName/subFolder + backstage.io/techdocs-ref: dir:. ``` The diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index 3f3c92d0de..e1533498d7 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -35,38 +35,64 @@ In your Backstage instance's `app-config.yaml`, set `techdocs.builder` from `'local'` to `'external'`. By doing this, TechDocs will not try to generate docs. Look at [TechDocs configuration](configuration.md) for reference. -## How to use URL Reader in TechDocs Prepare step? +## How to understand techdocs-ref annotation values -If TechDocs is configured to generate docs, it will first download the -repository associated with the `backstage.io/techdocs-ref` annotation defined in -the Entity's `catalog-info.yaml` file. This is also called the +If TechDocs is configured to generate docs, it will first download source files +based on the value of the `backstage.io/techdocs-ref` annotation defined in the +Entity's `catalog-info.yaml` file. This is also called the [Prepare](./concepts.md#techdocs-preparer) step. -There are two kinds of preparers or two ways of downloading these source files +We strongly recommend that the `backstage.io/techdocs-ref` annotation in each +documented catalog entity's `catalog-info.yaml` be set to `dir:.` in almost all +situations. This is because TechDocs is aligned with the "docs like code" +philosophy, whereby documentation should be authored and managed alongside the +source code of the underlying software itself. -- Preparer 1: Doing a `git clone` of the repository (also known as Common Git - Preparer) -- Preparer 2: Downloading an archive.zip or equivalent of the repository (also - known as URL Reader) +When you see `dir:.`, you can translate it to mean: -If `backstage.io/techdocs-ref` is equal to any of these - +- That the documentation source code lives in the same location as the + `catalog-info.yaml` file. +- That, in particular, the `mkdocs.yml` file is a sibling of `catalog-info.yaml` + (meaning, it is in the same directory) +- And that all of the source content of the documentation would be available if + one were to download the directory containing those two files (as well as all + sub-directories). -1. `github:https://githubhost.com/org/repo` -2. `gitlab:https://gitlabhost.com/org/repo` -3. `bitbucket:https://bitbuckethost.com/project/repo` -4. `azure/api:https://azurehost.com/org/project` +The directory tree of the entity would look something like this: -Then Common Git Preparer will be used i.e. a `git clone`. But the URL Reader is -a much faster way to do this step. Convert the `backstage.io/techdocs-ref` -values to the following - +``` +├── catalog-info.yaml +├── mkdocs.yml +└── docs + └── index.md +``` -1. `url:https://githubhost.com/org/repo/tree/` -2. `url:https://gitlabhost.com/org/repo/tree/` -3. `url:https://bitbuckethost.com/project/repo/src/` -4. `url:https://azurehost.com/organization/project/_git/repository` +If, for example, you wanted to keep a lean root directory, you could place your +`mkdocs.yml` file in a subdirectory and update the `backstage.io/techdocs-ref` +annotation value accordingly, e.g. to `dir:./sub-folder`: -Note that you can also provide a path to a non-root directory inside the -repository which contains the `docs/` directory. +``` +├── catalog-info.yaml +└── sub-folder + ├── mkdocs.yml + └── docs + └── index.md +``` + +In rare situations where your TechDocs source content is managed and stored in a +location completely separate from your `catalog-info.yaml`, you can instead +specify a URL location reference, the exact value of which will vary based on +the source code hosting provider. Notice that instead of the `dir:` prefix, the +`url:` prefix is used instead. For example: + +- **GitHub**: `url:https://githubhost.com/org/repo/tree/` +- **GitLab**: `url:https://gitlabhost.com/org/repo/tree/` +- **Bitbucket**: `url:https://bitbuckethost.com/project/repo/src/` +- **Azure**: `url:https://azurehost.com/organization/project/_git/repository` + +Note, just as it's possible to specify a subdirectory with the `dir:` prefix, +you can also provide a path to a non-root directory inside the repository which +contains the `mkdocs.yml` file and `docs/` directory. e.g. `url:https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend/examples/documented-component` diff --git a/docs/features/techdocs/using-cloud-storage.md b/docs/features/techdocs/using-cloud-storage.md index 119629915e..159137c879 100644 --- a/docs/features/techdocs/using-cloud-storage.md +++ b/docs/features/techdocs/using-cloud-storage.md @@ -150,6 +150,39 @@ permissions to: - `s3:ListBucket` - To retrieve bucket metadata - `s3:GetObject` - To retrieve files from the bucket +> Note: If you need to migrate documentation objects from an older-style path +> format including case-sensitive entity metadata, you will need to add some +> additional permissions to be able to perform the migration, including: +> +> - `s3:PutBucketAcl` (for copying files, +> [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html)) +> - `s3:DeleteObject` and `s3:DeleteObjectVersion` (for deleting migrated files, +> [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)) +> +> ...And you will need to ensure the permissions apply to the bucket itself, as +> well as all resources under the bucket. See the example policy below. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "TechDocsWithMigration", + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:GetObject", + "s3:DeleteObjectVersion", + "s3:ListBucket", + "s3:DeleteObject", + "s3:PutObjectAcl" + ], + "Resource": ["arn:aws:s3:::your-bucket", "arn:aws:s3:::your-bucket/*"] + } + ] +} +``` + **4a. (Recommended) Setup authentication the AWS way, using environment variables** diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index aa3851463f..7973a54ab6 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -35,7 +35,7 @@ If you want more control over the theme, and for example customize font sizes and margins, you can use the lower-level `createThemeOverrides` function exported by [@backstage/theme](https://www.npmjs.com/package/@backstage/theme) in combination with -[createMuiTheme](https://material-ui.com/customization/theming/#createmuitheme-options-args-theme) +[createTheme](https://material-ui.com/customization/theming/#createmuitheme-options-args-theme) from [@material-ui/core](https://www.npmjs.com/package/@material-ui/core). See the [@backstage/theme source](https://github.com/backstage/backstage/tree/master/packages/theme/src) diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 13b52181df..b01afac5c3 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -24,11 +24,9 @@ an easier path to make Pull Requests. Backstage provides the `@backstage/create-app` package to scaffold standalone instances of Backstage. You will need to have [Node.js](https://nodejs.org/en/download/) Active LTS Release installed -(currently v14), [Yarn](https://classic.yarnpkg.com/en/docs/install) and -[Python](https://www.python.org/downloads/) (although you likely have it -already). You will also need to have -[Docker](https://docs.docker.com/engine/install/) installed to use some features -like Software Templates and TechDocs. +(currently v14) and [Yarn](https://classic.yarnpkg.com/en/docs/install). You +will also need to have [Docker](https://docs.docker.com/engine/install/) +installed to use some features like Software Templates and TechDocs. Using `npx` you can then run the following to create an app in a chosen subdirectory of your current working directory: diff --git a/docs/integrations/bitbucket/discovery.md b/docs/integrations/bitbucket/discovery.md index fadb7c9f06..1538806e39 100644 --- a/docs/integrations/bitbucket/discovery.md +++ b/docs/integrations/bitbucket/discovery.md @@ -38,7 +38,11 @@ The target is composed of four parts: repositories prefixed with `service-`. - The path within each repository to find the catalog YAML file. This will usually be `/catalog-info.yaml` or a similar variation for catalog files - stored in the root directory of each repository. + stored in the root directory of each repository. If omitted, the default value + `catalog-info.yaml` will be used. E.g. given that `my-project`and `service-a` + exists, `https://bitbucket.mycompany.com/projects/my-project/repos/service-*/` + will result in: + `https://bitbucket.mycompany.com/projects/my-project/repos/service-a/catalog-info.yaml`. ## Custom repository processing diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index 0013c99c6b..fa34ca3d9a 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -1,116 +1,185 @@ --- id: roadmap -title: Project roadmap -description: Roadmap of Backstage Project +title: Roadmap +description: Roadmap of Backstage --- -## Current status +## The Backstage Roadmap -> Backstage is currently under rapid development. This means that you can expect -> APIs and features to evolve. It is also recommended that teams who adopt -> Backstage today [upgrade their installation](../cli/commands.md#versionsbump) -> as new [releases](https://github.com/backstage/backstage/releases) become -> available, as Backwards compatibility is not yet guaranteed. +Backstage is currently under rapid development. This page details the project’s +public roadmap, the result of ongoing collaboration between the core maintainers +and the broader Backstage community. Treat the roadmap as an ever-evolving guide +to keep us aligned as a community on: -## Phases +- Upcoming enhancements and benefits, +- Planning contributions and support, +- Planning the project’s adoption, +- Understanding what things are coming soon, +- Avoiding duplication of work -We have divided the project into three high-level _phases_: +### How to influence the roadmap -- 🐣 **Phase 1:** Extensible frontend platform (Done ✅) - You will be able to - easily create a single consistent UI layer for your internal infrastructure - and tools. A set of reusable - [UX patterns and components](https://backstage.io/storybook) help ensure a - consistent experience between tools. +As we evolve Backstage, we want you to contribute actively in the journey to +define the most effective developer experience in the world. -- 🐢 **Phase 2:** Software Catalog - ([alpha released](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha)) - - With a single catalog, Backstage makes it easy for a team to manage ten - services — and makes it possible for your company to manage thousands of them. +A roadmap is only useful if it captures real needs. If you have success stories, +feedback, or ideas, we want to hear from you! If you plan to work (or are +already working) on a new or existing feature, please let us know, so that we +can update the roadmap accordingly. We are also happy to share knowledge and +context that will help your feature land successfully. -- 🐇 **Phase 3:** Ecosystem (ongoing, see - [Plugin Marketplace](https://backstage.io/plugins)) - Everyone's - infrastructure stack is different. By fostering a vibrant community of - contributors we hope to provide an ecosystem of Open Source - plugins/integrations that allows you to pick the tools that match your stack. - -## Detailed roadmap - -If you have questions about the roadmap or want to provide feedback, we would -love to hear from you! Please create an -[Issue](https://github.com/backstage/backstage/issues/new/choose), ping us on -[Discord](https://discord.gg/EBHEGzX) or reach out directly at -[backstage-interest@spotify.com](mailto:backstage-interest@spotify.com). - -Want to help out? Awesome ❤️ Head over to +You can also head over to the [CONTRIBUTING](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) guidelines to get started. -### Ongoing work 🚧 +If you have specific questions about the roadmap, please create an +[issue](https://github.com/backstage/backstage/issues/new/choose), ping us on +[Discord](https://discord.gg/awD6SxgQ), or +[book time](http://calendly.com/spotify-backstage) with the Spotify team. -- **[Platform stabilization](https://github.com/backstage/backstage/milestone/19)** - - Stabilize the core of Backstage, including its core features, so that the - platform can be depended on for production use. After this, plugins will - require little-to-no maintenance. +### How to read the roadmap -- **[Kubernetes plugin for service owners](https://github.com/backstage/backstage/issues/2857)** - - Improve native support for Kubernetes, making it easier for service owners to - see and manage their services running in K8s, regardless if that's locally, in - AWS, GCS, Azure, or elsewhere. +The Backstage roadmap lays out both [“what’s next”](#whats-next) and +[“future work”](#future-work). With "next" we mean features planned for release +within the ongoing quarter starting in July until September 2021 included. With +"future" we mean features in the radar, but not yet scheduled. -- **[Search platform](../features/search/README.md)** - Evolve the basic search - functionality currently available into a platform that **a)** enables search - across the software catalog, TechDocs, and any other information exposed by - plugins, and **b)** supports a variety of search engine technologies. +The long-term roadmap (12 - 36 months) is not detailed in the public roadmap. +Third-party contributions are also not currently included in the roadmap. Let us +know about any ongoing developments and we’re happy to include it here as well. -- **[Software Templates V2](https://github.com/backstage/backstage/issues/2771)** - - Expand the templates to make the steps more composable by adding the ability - to add more steps for custom logic, including webhooks and using authorization - from integrations. +### Roadmap evolution -### Future work 🔮 +Will this roadmap change? Obviously! -- **Golden Path for Plugin Development** - Create an easy, standardized way for - developers to build plugins that will encourage contributions and lead to a - richer ecosystem for everyone. +Roadmap are always evolving and ours is no different; you can expect to see this +updated roughly every month. -- **[GraphQL API](https://github.com/backstage/backstage/milestone/13)** - A - GraphQL API will open up the rich metadata provided by Backstage in a single - query. Plugins can easily query this API as well as extend the model where - needed. +## What’s next -- **Inter-Plugin Communication** - **[Under consideration]** Establish more - clearly defined patterns for plugins to communicate. +The feature set below is planned for the ongoing quarter, and grouped by theme. +The list order doesn’t necessarily reflect priority, and the development/release +cycle will vary based on maintainer schedules. -- **Improved Access Control** - **[Under consideration]** Provide finer grained - access controls and management for better control of the platform user - experience. +### Backstage Core -### Plugins +The following features are planned for release: -Building and maintaining [plugins](https://backstage.io/plugins) is the work of -the entire Backstage community. +- **Composable homepage:** We’re seeing lots of interest from the community in + reusable components to build a homepage experience where users can easily + surface what they might find useful to start their tasks. Check out the + [milestone](https://github.com/backstage/backstage/milestone/34) for further + details. +- **Improved responsiveness:** Check out the + [RFC here](https://github.com/backstage/backstage/issues/6318) for further + details on how to improve the responsiveness for Backstage's UI. -A list of plugins that are in development is -[available here](https://github.com/backstage/backstage/issues?q=is%3Aissue+is%3Aopen+label%3Aplugin+sort%3Areactions-%2B1-desc). -We strongly recommend to upvote 👍 plugins you are interested in. This helps us -and the community prioritize what plugins to build. +### Software Templates -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. +The following features are planned for release:: -### Community Initiatives 🧑‍🤝‍🧑 +- **Re-creation/resubmission in case of failure:** Speed up productivity by + allowing developers to relaunch a project after a failure or any unexpected + problem. In the current version, this task requires retyping and a full + re-creation from scratch. +- **Performance and usability improvements for contributors:** Reach a relevant + improvement in templating's performance through the replacement of + [handlebars](https://handlebarsjs.com/). Other replacements will be considered + as part of this task (possibly + [cookiecutter](https://cookiecutter.readthedocs.io/)) for easier software + template creation, allowing more contributors to reach their goals without + having to learn new tooling. +- **Improved extensibility through inclusion:** Make software templates more + maintainable and extensible by adding `$include` support for parameters. +- **Authenticated job creation:** Created jobs will be able to run with an + authenticated user with all actions tracked for future consumption and + evidence. Track users creating jobs and make “jobs created by me” reporting + available. -- [**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. +### Software Catalog -- **Backstage Hackathons** - (Coming soon) Open to everyone in our Backstage - community, a celebration of you, the project and building awesome things - together +The following features are planned for release: -### Completed milestones ✅ +- **Request For Comments (RFC) for composability improvements (routing):** + Enable plugins to be auto-added and make plugin installation and upgrades + easier for all Backstage users. This includes information card layouts, entity + pages containing content and hooking the external header, considering the + support of a separate deployment, and configuration for plugins. +- **Removing duplicated entities in catalog:** As any adopter knows, a software + catalog can contain thousands or more entities and it is very important to + avoid duplications in naming to prevent failures. With this development task, + two entities with the same name won't be allowed as described + [here](https://github.com/backstage/backstage/issues/4760). +- **Connecting identity to ownership to prepare for role-based access control + ([RBAC](https://en.wikipedia.org/wiki/Role-based_access_control)):** This is a + first step to supporting RBAC for the software catalog (see the + [future work section](#future-work) for further details). Provide each entity + within the software catalog with a recognized owner. +- **Catalog performance improvements through improved caching:** Fix the + performance gaps in the catalog processor, which currently doesn’t have a + strong caching mechanism. The current version often requires fetching a + relevant amount of data, especially at scale. +### Search + +The following features are planned for release: + +- ElasticSearch integration: Add ElasticSearch to the Search Platform as the + underlying search engine. Check out the + [milestone here](https://github.com/backstage/backstage/milestone/27) for + further details. + +### TechDocs + +The following features are planned for release: + +- **TechDocs beta release:** Fix remaining bugs to get TechDocs to Beta. Check + out the [milestone here](https://github.com/backstage/backstage/milestone/29) + for further details. + +## Future work + +The following feature list doesn’t represent a commitment to develop and the +list order doesn’t reflect any priority or importance. But these features are on +the maintainers’ radar, with clear interest expressed by the community. + +- **Improved UX design:** Provide a better Backstage user experience through + visual guidelines and templates, especially navigation across plug-ins and + portal functionalities. +- **Catalog composability (routing):** Follow up development after the RFC + planned for the ongoing quarter (see [what’s next](#whats-next) for further + details). +- **Catalog-import improvements:** Provide a faster (scalability) and better + (more features like move/rename) way to import entities into the Software + Catalog. Importing items in the Software Catalog is crucial for creating a + Backstage proof-of-concept or testing/planning for broader organizational + adoption. This enhancement better supports getting developers to use Backstage + with less effort and customization. +- **Catalog improvements:** Add pagination and sourcing to Software Catalog. +- **[GraphQL](https://graphql.org/) support:** Introduce the ability to query + Backstage backend services with a standard query language for APIs. +- **Software templates performance improvements through decoupling a separate + worker:** Improve performance through decoupling resource-consuming services + and making them asynchronous. In the current version, project auto-creation + through the Software Templating system can consume a lot of resources and + bottleneck many concurrent projects created simultaneously. +- **API discovery and documentation:** Add better support for the + [gRPC](https://grpc.io/). +- **Adding TechDocs search to the Search Platform:** Having this capability in + place will provide a better and new major version of the Search Platform + (v3.0). You can refer to the + [milestone here](https://github.com/backstage/backstage/milestone/28) for + further details. +- **TechDocs GA release:** Work toward enhancements necessary to get TechDocs to + general availability. Check out the + [milestone here](https://github.com/backstage/backstage/milestone/30) for + further details. + +## Completed milestones + +Read more about the completed (and released) features for reference. + +- [[Search] Out-of-the-Box Implementation (Alpha)](https://github.com/backstage/backstage/milestone/26) - [Deploy a product demo at `demo.backstage.io`](https://demo.backstage.io) - [Kubernetes plugin - v1](https://github.com/backstage/backstage/tree/master/plugins/kubernetes) - [Helm charts](https://github.com/backstage/backstage/tree/master/contrib/chart/backstage) diff --git a/docs/plugins/structure-of-a-plugin.md b/docs/plugins/structure-of-a-plugin.md index beffcdb313..99a55745c5 100644 --- a/docs/plugins/structure-of-a-plugin.md +++ b/docs/plugins/structure-of-a-plugin.md @@ -99,15 +99,14 @@ You may tweak these components, rename them and/or replace them completely. ## Connecting the plugin to the Backstage app -There are three things needed for a Backstage app to start making use of a -plugin. +There are two things needed for a Backstage app to start making use of a plugin. 1. Add plugin as dependency in `app/package.json` 2. Import and use one or more plugin extensions, for example in `app/src/App.tsx`. -Luckily these three steps happen automatically when you create a plugin with the -Backstage CLI. +Luckily both of these steps happen automatically when you create a plugin with +the Backstage CLI. ## Talking to the outside world diff --git a/microsite/blog/2021-07-26-software-templates-are-now-in-beta.md b/microsite/blog/2021-07-26-software-templates-are-now-in-beta.md new file mode 100644 index 0000000000..b646fbdb22 --- /dev/null +++ b/microsite/blog/2021-07-26-software-templates-are-now-in-beta.md @@ -0,0 +1,68 @@ +--- +title: Software Templates is now in Beta +author: Ben Lambert, Spotify +authorURL: https://github.com/benjdlambert +authorImageURL: https://avatars.githubusercontent.com/u/3645856?v=4 +--- + +![Software Templates in Beta](assets/21-07-26/backstage-software-templates-beta.gif) + +**TLDR**; At a high level, Backstage performs three main jobs: [Create, Manage, and Explore](https://backstage.io/blog/2021/05/20/adopting-backstage#three-jobs-create-manage-explore). Throughout the year, we’ve been focussed on improving the stability and scalability of these areas while enhancing the feature sets based upon requests from the community. Software Templates — which enable push-button deployments with all your standards and best practices built-in — is our first feature-complete release candidate to graduate to beta. Read on to learn how this release improves template customization and flexibility, as well as performance. + + + +Let’s rewind a little bit, around a year in fact. Backstage had been open sourced, and we released our first version of Software Templates and our Scaffolder plugin. + +In case you missed it, [Software Templates](https://backstage.io/blog/2020/08/05/announcing-backstage-software-templates) are part of the Create feature set, where you can set up Backstage to give your engineers the ability to spin up a new microservice, website, or any other software component with your organization’s best practices built-in, right from the start. + +Back when we released the first version of these templates, with the `apiVersion` `backstage.io/v1alpha1`, they were a little restrictive in what they could do. The generated repository could only have one template source and it was restricted to only being [cookiecutter](https://github.com/cookiecutter/cookiecutter) templates. And it had to fit into the three stages of templating which was `Prepare`, `Template`, and `Publish`. + +We [opened up for feedback](https://github.com/backstage/backstage/issues/2771) from the community knowing that this wasn’t going to be the final version, but something of a stepping stone to where we want to be in the future. + +And now we come to today… + +## Anddddd… Action(s)! 🎬 + +Following the removal of the previously deprecated `backstage.io/v1alpha1` templates, today we’re officially announcing the beta version of Software Templates, or `backstage.io/v1beta2`. + +With it comes an entirely new architecture to the Software Templates functionality, and a load of new exciting features, which I’ll dig into a little deeper. + +### Template actions + +We’ve totally opened up the ability to compose your own workflows for each Template that you have registered in Software Templates. This means no restrictions on where your template skeleton is kept, and no restrictions on what your workflow should look like. + +Template Actions are customizable JavaScript functions that allow you to extend the capabilities of the Software Templates by adding your own business logic or reusing some of our Built-In actions. + +![New template syntax with actions](assets/21-07-26/example-template-code.png) + +_An example of the new template syntax with steps and parameters_ + +The workflow for Software Templates are now step-based, and each Software Template can have a customizable amount of steps which will in turn call these new actions. + +![New steps being rendered in the frontend](assets/21-07-26/steps-running.gif) + +_An example of a Template with customizable steps_ + +These actions are very heavily inspired by GitHub Actions and GitHub Workflows, and we’ve given back a lot of control to the template authors so they can build the boilerplate and push the code however they want. + +### Custom UI extensions + +A large part of the Software Templates feature is the form that we use to collect user input which is then passed on to these new actions. Sometimes, it makes sense that Template Authors want to provide their own React components which can be rendered in the frontend to maybe do some more complex things like calling internal APIs to provide autocomplete. + +This is now possible with the new `ScaffolderFieldExtensions`. + +![Custom UI extensions](assets/21-07-26/custom-components.gif) + +_An example of `ScaffolderFieldExtension` is the `OwnerPicker` component which can automatically add options and suggest typeahead with data from an async API request_ + +Template Authors can create their own components to provide data to the custom actions in any way you see fit, and even override our own built in ones too like the `RepoUrlPicker`. + +### Horizontal scalability + +The Scaffolder Service and Software Templates are now horizontally scalable, coordinating work between your deployed backend machines. This means now that the number of instances of the `@backstage/plugin-scaffolder-backend` plugin you have, is the same amount of jobs that you can have in parallel. This ensures that your tasks are handled quickly and reliably, while providing great feedback in the process. + +## Try out the new templates + +We’re still on the journey to making the Software Templates a great user experience for both authors and developers — but we’re not done yet, so watch this space for new exciting features to come! + +In the meantime, make sure to visit the documentation for [building templates](https://backstage.io/docs/features/software-templates/adding-templates) or creating your own [custom actions](https://backstage.io/docs/features/software-templates/writing-custom-actions). diff --git a/microsite/blog/assets/21-07-26/backstage-software-templates-beta.gif b/microsite/blog/assets/21-07-26/backstage-software-templates-beta.gif new file mode 100644 index 0000000000..f67113f44c Binary files /dev/null and b/microsite/blog/assets/21-07-26/backstage-software-templates-beta.gif differ diff --git a/microsite/blog/assets/21-07-26/custom-components.gif b/microsite/blog/assets/21-07-26/custom-components.gif new file mode 100644 index 0000000000..d9c78db33f Binary files /dev/null and b/microsite/blog/assets/21-07-26/custom-components.gif differ diff --git a/microsite/blog/assets/21-07-26/example-template-code.png b/microsite/blog/assets/21-07-26/example-template-code.png new file mode 100644 index 0000000000..1205adf657 Binary files /dev/null and b/microsite/blog/assets/21-07-26/example-template-code.png differ diff --git a/microsite/blog/assets/21-07-26/steps-running.gif b/microsite/blog/assets/21-07-26/steps-running.gif new file mode 100644 index 0000000000..d824464bac Binary files /dev/null and b/microsite/blog/assets/21-07-26/steps-running.gif differ diff --git a/microsite/core/Footer.js b/microsite/core/Footer.js index 8e69b7ff6f..1ea591b1d5 100644 --- a/microsite/core/Footer.js +++ b/microsite/core/Footer.js @@ -44,6 +44,10 @@ class Footer extends React.Component { Contributing + Adopting + + Community Sessions + Subscribe to our newsletter diff --git a/microsite/data/plugins/xcmetrics.yaml b/microsite/data/plugins/xcmetrics.yaml new file mode 100644 index 0000000000..f2f4f7c013 --- /dev/null +++ b/microsite/data/plugins/xcmetrics.yaml @@ -0,0 +1,9 @@ +--- +title: XCMetrics +author: Spotify +authorUrl: https://github.com/spotify +category: Monitoring +description: Discover valuable insights hiding inside Xcode’s build logs. +documentation: https://xcmetrics.io/ +iconUrl: img/xcmetrics-icon.png +npmPackageName: '@backstage/plugin-xcmetrics' diff --git a/microsite/package.json b/microsite/package.json index eee549fb70..532bb62d15 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -16,7 +16,7 @@ "lock:check": "yarn-lock-check" }, "devDependencies": { - "@spotify/prettier-config": "^10.0.0", + "@spotify/prettier-config": "^11.0.0", "docusaurus": "^2.0.0-alpha.70", "js-yaml": "^4.1.0", "prettier": "^2.3.2", diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index d7325bb234..ec80bbc01f 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -212,9 +212,9 @@ class Index extends React.Component { Backstage Software Templates{' '} - (alpha) + (beta) Standards can set you free @@ -292,7 +292,7 @@ class Index extends React.Component { Build your own software templates Contribute diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 5999524073..c22a7e961d 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -80,7 +80,8 @@ "features/search/search-overview", "features/search/getting-started", "features/search/concepts", - "features/search/architecture" + "features/search/architecture", + "features/search/search-engines" ] }, { diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css index 2c8b46ff00..393a5af118 100644 --- a/microsite/static/css/custom.css +++ b/microsite/static/css/custom.css @@ -288,6 +288,16 @@ td { .tocToggler { display: none; } + + .docsSliderActive .toc section .navGroups { + padding-top: 0; + padding-bottom: 0; + } + + .docsSliderActive.docsNavContainer { + background-color: #121212; + padding-bottom: 0; + } } /* content */ diff --git a/microsite/static/img/backstage-k8s.svg b/microsite/static/img/backstage-k8s.svg index 2796a396e7..28b6ef8f92 100644 --- a/microsite/static/img/backstage-k8s.svg +++ b/microsite/static/img/backstage-k8s.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/microsite/static/img/backstage-software-catalog.svg b/microsite/static/img/backstage-software-catalog.svg index 101439497b..5cad498d35 100644 --- a/microsite/static/img/backstage-software-catalog.svg +++ b/microsite/static/img/backstage-software-catalog.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/microsite/static/img/backstage-software-templates.svg b/microsite/static/img/backstage-software-templates.svg index 3984cd2870..e64428de82 100644 --- a/microsite/static/img/backstage-software-templates.svg +++ b/microsite/static/img/backstage-software-templates.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/microsite/static/img/backstage-techdocs.svg b/microsite/static/img/backstage-techdocs.svg index aa9362b1bc..643cde325c 100644 --- a/microsite/static/img/backstage-techdocs.svg +++ b/microsite/static/img/backstage-techdocs.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/microsite/static/img/rails-icon.png b/microsite/static/img/rails-icon.png index f7b8b69bd9..04f63766fe 100644 Binary files a/microsite/static/img/rails-icon.png and b/microsite/static/img/rails-icon.png differ diff --git a/microsite/static/img/xcmetrics-icon.png b/microsite/static/img/xcmetrics-icon.png new file mode 100644 index 0000000000..225ee6e147 Binary files /dev/null and b/microsite/static/img/xcmetrics-icon.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 1da9288808..0f7ddb9c60 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -909,10 +909,10 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@spotify/prettier-config@^10.0.0": - version "10.0.0" - resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-10.0.0.tgz#fa076d98d2e7e6c53dd3d86a696307a7010bd056" - integrity sha512-VYOdo8P7lIScAkl02nB9KpUAuOYMManryBIBuKJkAw5D3aVtLobfmdIKvdV6MqEmGMEQPbn7w/UpnjJYhUH+IA== +"@spotify/prettier-config@^11.0.0": + version "11.0.0" + resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-11.0.0.tgz#d91e0546a8c1c0f7299e2edc7e44306e9be210f6" + integrity sha512-dOI13j1uHMZkRxhZuge/ugOE7Aqcg7Nxki932lDZuXyY4G8CGxkc/66PeQ8pR4PCzThHORXo7Ptvau6bh101lQ== "@types/cheerio@^0.22.8": version "0.22.23" diff --git a/mkdocs.yml b/mkdocs.yml index 4d984e63e3..bd70104abc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,6 +64,7 @@ nav: - Getting Started: 'features/search/getting-started.md' - Concepts: 'features/search/concepts.md' - Search Architecture: 'features/search/architecture.md' + - Search Engines: 'features/search/search-engines.md' - TechDocs: - Overview: 'features/techdocs/README.md' - Getting Started: 'features/techdocs/getting-started.md' diff --git a/package.json b/package.json index 93517d3374..ea1cf0c9b4 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ ] }, "resolutions": { + "**/@graphql-codegen/cli/**/ws": "^7.4.6", "**/@roadiehq/**/@backstage/core": "*", "**/@roadiehq/**/@backstage/plugin-catalog": "*", "**/@roadiehq/**/@backstage/catalog-model": "*", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index cc67b78f44..14927117ab 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,117 @@ # example-app +## 0.2.40 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.7.7 + - @backstage/plugin-catalog@0.6.10 + - @backstage/core-components@0.3.0 + - @backstage/core-plugin-api@0.1.5 + - @backstage/plugin-api-docs@0.6.5 + - @backstage/plugin-scaffolder@0.10.3 + - @backstage/plugin-search@0.4.6 + - @backstage/plugin-cost-insights@0.11.3 + - @backstage/plugin-kubernetes@0.4.10 + - @backstage/plugin-lighthouse@0.2.22 + - @backstage/plugin-pagerduty@0.3.10 + - @backstage/plugin-techdocs@0.10.3 + - @backstage/search-common@0.1.3 + - @backstage/core-app-api@0.1.7 + - @backstage/integration-react@0.1.6 + - @backstage/plugin-badges@0.2.7 + - @backstage/plugin-catalog-import@0.5.16 + - @backstage/plugin-catalog-react@0.4.1 + - @backstage/plugin-circleci@0.2.21 + - @backstage/plugin-cloudbuild@0.2.21 + - @backstage/plugin-code-coverage@0.1.9 + - @backstage/plugin-explore@0.3.12 + - @backstage/plugin-gcp-projects@0.3.2 + - @backstage/plugin-github-actions@0.4.15 + - @backstage/plugin-graphiql@0.2.14 + - @backstage/plugin-jenkins@0.5.2 + - @backstage/plugin-kafka@0.2.13 + - @backstage/plugin-newrelic@0.3.2 + - @backstage/plugin-org@0.3.19 + - @backstage/plugin-rollbar@0.3.11 + - @backstage/plugin-sentry@0.3.17 + - @backstage/plugin-shortcuts@0.1.6 + - @backstage/plugin-tech-radar@0.4.4 + - @backstage/plugin-todo@0.1.7 + - @backstage/plugin-user-settings@0.3.3 + +## 0.2.39 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@0.10.2 + - @backstage/core-components@0.2.0 + - @backstage/plugin-catalog@0.6.9 + - @backstage/plugin-catalog-react@0.4.0 + - @backstage/cli@0.7.6 + - @backstage/core-app-api@0.1.6 + - @backstage/core-plugin-api@0.1.4 + - @backstage/integration-react@0.1.5 + - @backstage/theme@0.2.9 + - @backstage/plugin-api-docs@0.6.4 + - @backstage/plugin-badges@0.2.6 + - @backstage/plugin-catalog-import@0.5.15 + - @backstage/plugin-circleci@0.2.20 + - @backstage/plugin-cloudbuild@0.2.20 + - @backstage/plugin-code-coverage@0.1.8 + - @backstage/plugin-cost-insights@0.11.2 + - @backstage/plugin-explore@0.3.11 + - @backstage/plugin-gcp-projects@0.3.1 + - @backstage/plugin-github-actions@0.4.14 + - @backstage/plugin-graphiql@0.2.13 + - @backstage/plugin-jenkins@0.5.1 + - @backstage/plugin-kafka@0.2.12 + - @backstage/plugin-kubernetes@0.4.9 + - @backstage/plugin-lighthouse@0.2.21 + - @backstage/plugin-newrelic@0.3.1 + - @backstage/plugin-org@0.3.18 + - @backstage/plugin-pagerduty@0.3.9 + - @backstage/plugin-rollbar@0.3.10 + - @backstage/plugin-search@0.4.5 + - @backstage/plugin-sentry@0.3.16 + - @backstage/plugin-shortcuts@0.1.5 + - @backstage/plugin-tech-radar@0.4.3 + - @backstage/plugin-techdocs@0.10.2 + - @backstage/plugin-todo@0.1.6 + - @backstage/plugin-user-settings@0.3.2 + +## 0.2.37 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@0.6.7 + - @backstage/plugin-catalog-react@0.3.0 + - @backstage/plugin-scaffolder@0.10.1 + - @backstage/plugin-techdocs@0.10.0 + - @backstage/plugin-jenkins@0.5.0 + - @backstage/plugin-user-settings@0.3.0 + - @backstage/plugin-search@0.4.3 + - @backstage/cli@0.7.4 + - @backstage/plugin-api-docs@0.6.2 + - @backstage/plugin-badges@0.2.5 + - @backstage/plugin-catalog-import@0.5.13 + - @backstage/plugin-circleci@0.2.19 + - @backstage/plugin-cloudbuild@0.2.19 + - @backstage/plugin-code-coverage@0.1.7 + - @backstage/plugin-explore@0.3.10 + - @backstage/plugin-github-actions@0.4.13 + - @backstage/plugin-kafka@0.2.11 + - @backstage/plugin-kubernetes@0.4.8 + - @backstage/plugin-lighthouse@0.2.20 + - @backstage/plugin-org@0.3.17 + - @backstage/plugin-pagerduty@0.3.8 + - @backstage/plugin-rollbar@0.3.9 + - @backstage/plugin-sentry@0.3.15 + - @backstage/plugin-todo@0.1.5 + ## 0.2.36 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index b26e94fc26..1260deed1a 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,52 +1,54 @@ { "name": "example-app", - "version": "0.2.36", + "version": "0.2.40", "private": true, "bundled": true, "dependencies": { "@backstage/catalog-model": "^0.9.0", - "@backstage/cli": "^0.7.2", - "@backstage/core-app-api": "^0.1.3", - "@backstage/core-components": "^0.1.5", - "@backstage/core-plugin-api": "^0.1.3", - "@backstage/integration-react": "^0.1.4", - "@backstage/plugin-api-docs": "^0.6.1", - "@backstage/plugin-badges": "^0.2.4", - "@backstage/plugin-catalog": "^0.6.6", - "@backstage/plugin-catalog-import": "^0.5.12", - "@backstage/plugin-catalog-react": "^0.2.6", - "@backstage/plugin-circleci": "^0.2.18", - "@backstage/plugin-cloudbuild": "^0.2.18", - "@backstage/plugin-code-coverage": "^0.1.6", - "@backstage/plugin-cost-insights": "^0.11.0", - "@backstage/plugin-explore": "^0.3.9", - "@backstage/plugin-gcp-projects": "^0.3.0", - "@backstage/plugin-github-actions": "^0.4.12", - "@backstage/plugin-graphiql": "^0.2.12", - "@backstage/plugin-jenkins": "^0.4.7", - "@backstage/plugin-kafka": "^0.2.10", - "@backstage/plugin-kubernetes": "^0.4.7", - "@backstage/plugin-lighthouse": "^0.2.19", - "@backstage/plugin-newrelic": "^0.3.0", - "@backstage/plugin-org": "^0.3.16", - "@backstage/plugin-pagerduty": "0.3.7", - "@backstage/plugin-rollbar": "^0.3.8", - "@backstage/plugin-scaffolder": "^0.10.0", - "@backstage/plugin-search": "^0.4.2", - "@backstage/plugin-sentry": "^0.3.14", - "@backstage/plugin-shortcuts": "^0.1.4", - "@backstage/plugin-tech-radar": "^0.4.1", - "@backstage/plugin-techdocs": "^0.9.9", - "@backstage/plugin-todo": "^0.1.4", - "@backstage/plugin-user-settings": "^0.2.12", - "@backstage/theme": "^0.2.8", - "@material-ui/core": "^4.11.0", + "@backstage/cli": "^0.7.7", + "@backstage/core-app-api": "^0.1.7", + "@backstage/core-components": "^0.3.0", + "@backstage/core-plugin-api": "^0.1.5", + "@backstage/integration-react": "^0.1.6", + "@backstage/plugin-api-docs": "^0.6.5", + "@backstage/plugin-badges": "^0.2.7", + "@backstage/plugin-catalog": "^0.6.10", + "@backstage/plugin-catalog-import": "^0.5.16", + "@backstage/plugin-catalog-react": "^0.4.1", + "@backstage/plugin-circleci": "^0.2.21", + "@backstage/plugin-cloudbuild": "^0.2.21", + "@backstage/plugin-code-coverage": "^0.1.9", + "@backstage/plugin-cost-insights": "^0.11.3", + "@backstage/plugin-explore": "^0.3.12", + "@backstage/plugin-gcp-projects": "^0.3.2", + "@backstage/plugin-github-actions": "^0.4.15", + "@backstage/plugin-graphiql": "^0.2.14", + "@backstage/plugin-jenkins": "^0.5.2", + "@backstage/plugin-kafka": "^0.2.13", + "@backstage/plugin-kubernetes": "^0.4.10", + "@backstage/plugin-lighthouse": "^0.2.22", + "@backstage/plugin-newrelic": "^0.3.2", + "@backstage/plugin-org": "^0.3.19", + "@backstage/plugin-pagerduty": "0.3.10", + "@backstage/plugin-rollbar": "^0.3.11", + "@backstage/plugin-scaffolder": "^0.10.3", + "@backstage/plugin-search": "^0.4.6", + "@backstage/plugin-sentry": "^0.3.17", + "@backstage/plugin-shortcuts": "^0.1.6", + "@backstage/plugin-tech-radar": "^0.4.4", + "@backstage/plugin-techdocs": "^0.10.3", + "@backstage/plugin-todo": "^0.1.7", + "@backstage/plugin-user-settings": "^0.3.3", + "@backstage/search-common": "^0.1.3", + "@backstage/theme": "^0.2.9", + "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.5.3", - "@roadiehq/backstage-plugin-buildkite": "^1.0.4", - "@roadiehq/backstage-plugin-github-insights": "^1.1.15", - "@roadiehq/backstage-plugin-github-pull-requests": "^1.0.8", - "@roadiehq/backstage-plugin-travis-ci": "^1.0.4", + "@roadiehq/backstage-plugin-buildkite": "^1.0.6", + "@roadiehq/backstage-plugin-github-insights": "^1.1.20", + "@roadiehq/backstage-plugin-github-pull-requests": "^1.0.10", + "@roadiehq/backstage-plugin-travis-ci": "^1.0.8", "history": "^5.0.0", "prop-types": "^15.7.2", "react": "^16.12.0", @@ -58,7 +60,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/test-utils": "^0.1.14", + "@backstage/test-utils": "^0.1.16", "@testing-library/cypress": "^7.0.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", @@ -66,7 +68,7 @@ "@types/jest": "^26.0.7", "@types/jquery": "^3.3.34", "@types/node": "^14.14.32", - "@types/react-dom": "^16.9.8", + "@types/react-dom": "*", "@types/zen-observable": "^0.8.0", "cross-env": "^7.0.0", "cypress": "^7.3.0", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 16107a6cc0..d84a7341bc 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -40,6 +40,8 @@ import { isKind, EntityHasResourcesCard, EntityOrphanWarning, + EntityProcessingErrorsPanel, + hasCatalogProcessingErrors, isOrphan, } from '@backstage/plugin-catalog'; import { @@ -135,6 +137,13 @@ const EntityLayoutWrapper = (props: { children?: ReactNode }) => { ); }; +/** + * NOTE: This page is designed to work on small screens such as mobile devices. + * This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`, + * since this does not default. If no breakpoints are used, the items will equitably share the asvailable space. + * https://material-ui.com/components/grid/#basic-grid. + */ + export const cicdContent = ( @@ -224,6 +233,14 @@ const overviewContent = ( + + + + + + + + @@ -292,10 +309,10 @@ const serviceEntityPage = ( - + - + @@ -303,10 +320,10 @@ const serviceEntityPage = ( - + - + @@ -431,15 +448,17 @@ const apiPage = ( - + - - - - - - + + + + + + + + diff --git a/packages/app/src/components/search/SearchPage.tsx b/packages/app/src/components/search/SearchPage.tsx index 35c4a4ac1c..cf4e610b80 100644 --- a/packages/app/src/components/search/SearchPage.tsx +++ b/packages/app/src/components/search/SearchPage.tsx @@ -14,35 +14,88 @@ * limitations under the License. */ -import React from 'react'; +import React, { useState } from 'react'; import { makeStyles, Theme, Grid, List, Paper } from '@material-ui/core'; - +import Pagination from '@material-ui/lab/Pagination'; import { CatalogResultListItem } from '@backstage/plugin-catalog'; import { SearchBar, SearchFilter, SearchResult, + SearchType, DefaultResultListItem, } from '@backstage/plugin-search'; import { Content, Header, Lifecycle, Page } from '@backstage/core-components'; +import { DocsResultListItem } from '@backstage/plugin-techdocs'; +import { SearchResultSet } from '@backstage/search-common'; const useStyles = makeStyles((theme: Theme) => ({ bar: { padding: theme.spacing(1, 0), }, - filters: { - padding: theme.spacing(2), - }, filter: { '& + &': { marginTop: theme.spacing(2.5), }, }, + filters: { + padding: theme.spacing(2), + }, })); +// TODO: Move this into the search plugin once pagination is natively supported. +// See: https://github.com/backstage/backstage/issues/6062 +const SearchResultList = ({ results }: SearchResultSet) => { + const pageSize = 10; + const [page, setPage] = useState(1); + const changePage = (_: any, pageIndex: number) => { + setPage(pageIndex); + }; + const pageAmount = Math.ceil((results.length || 0) / pageSize); + return ( + <> + + {results + .slice(pageSize * (page - 1), pageSize * page) + .map(({ type, document }) => { + switch (type) { + case 'software-catalog': + return ( + + ); + case 'techdocs': + return ( + + ); + default: + return ( + + ); + } + })} + + + + ); +}; + const SearchPage = () => { const classes = useStyles(); - return (
} /> @@ -55,6 +108,11 @@ const SearchPage = () => { + { - {({ results }) => ( - - {results.map(({ type, document }) => { - switch (type) { - case 'software-catalog': - return ( - - ); - default: - return ( - - ); - } - })} - - )} + {({ results }) => } diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 93016bd13c..f6f61133ea 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/backend-common +## 0.8.8 + +### Patch Changes + +- 6aa7c3db7: bump node-tar version to the latest +- Updated dependencies + - @backstage/config@0.1.6 + - @backstage/integration@0.5.9 + - @backstage/config-loader@0.6.6 + +## 0.8.7 + +### Patch Changes + +- f25357273: Implement the etag functionality in the `readUrl` method of `FetchUrlReader`. +- bdd6ab5f1: It's possible to customize the request logging handler when building the service. For example in your `backend` + + ``` + const service = createServiceBuilder(module) + .loadConfig(config) + .setRequestLoggingHandler((logger?: Logger): RequestHandler => { + const actualLogger = (logger || getRootLogger()).child({ + type: 'incomingRequest', + }); + return expressWinston.logger({ ... + ``` + +## 0.8.6 + +### Patch Changes + +- 5f6f2fd96: Support a `ensureExists` config option to skip ensuring a configured database exists. This allows deployment scenarios where + limited permissions are given for provisioned databases without privileges to create new databases. If set to `false`, the + database connection will not be validated prior to use which means the backend will not attempt to create the database if it + doesn't exist. You can configure this in your app-config.yaml: + + ```yaml + backend: + database: + ensureExists: false + ``` + + This defaults to `true` if unspecified. You can also configure this per plugin connection and will override the base option. + +- ad93bb035: Document the default behavior of `statusCheck` option in `createStatusCheckRouter`. +- ae84b20cf: Revert the upgrade to `fs-extra@10.0.0` as that seemed to have broken all installs inexplicably. +- Updated dependencies + - @backstage/config-loader@0.6.5 + ## 0.8.5 ### Patch Changes diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 94f1147b5a..2652dad122 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -32,6 +32,8 @@ import { Server } from 'http'; import * as winston from 'winston'; import { Writable } from 'stream'; +// Warning: (ae-missing-release-tag) "AzureUrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class AzureUrlReader implements UrlReader { constructor( @@ -40,20 +42,31 @@ export class AzureUrlReader implements UrlReader { treeResponseFactory: ReadTreeResponseFactory; }, ); + // Warning: (ae-forgotten-export) The symbol "ReaderFactory" needs to be exported by the entry point index.d.ts + // // (undocumented) static factory: ReaderFactory; // (undocumented) read(url: string): Promise; + // Warning: (ae-forgotten-export) The symbol "ReadTreeOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) readTree(url: string, options?: ReadTreeOptions): Promise; + // Warning: (ae-forgotten-export) The symbol "ReadUrlOptions" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "ReadUrlResponse" needs to be exported by the entry point index.d.ts + // // (undocumented) readUrl(url: string, _options?: ReadUrlOptions): Promise; + // Warning: (ae-forgotten-export) The symbol "SearchOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) search(url: string, options?: SearchOptions): Promise; // (undocumented) toString(): string; } +// Warning: (ae-missing-release-tag) "BitbucketUrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class BitbucketUrlReader implements UrlReader { constructor( @@ -76,60 +89,92 @@ export class BitbucketUrlReader implements UrlReader { toString(): string; } +// Warning: (ae-missing-release-tag) "CacheClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export interface CacheClient { delete(key: string): Promise; get(key: string): Promise; + // Warning: (ae-forgotten-export) The symbol "CacheSetOptions" needs to be exported by the entry point index.d.ts set(key: string, value: JsonValue, options?: CacheSetOptions): Promise; } +// Warning: (ae-missing-release-tag) "CacheManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class CacheManager { + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen forPlugin(pluginId: string): PluginCacheManager; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (ae-forgotten-export) The symbol "CacheManagerOptions" needs to be exported by the entry point index.d.ts static fromConfig( config: Config, options?: CacheManagerOptions, ): CacheManager; } +// Warning: (ae-missing-release-tag) "coloredFormat" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const coloredFormat: winston.Logform.Format; +// Warning: (ae-missing-release-tag) "ContainerRunner" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface ContainerRunner { // (undocumented) runContainer(opts: RunContainerOptions): Promise; } +// Warning: (ae-missing-release-tag) "createDatabase" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated export const createDatabase: typeof createDatabaseClient; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "createDatabaseClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function createDatabaseClient( dbConfig: Config, overrides?: Partial, ): Knex; +// Warning: (ae-missing-release-tag) "createRootLogger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function createRootLogger( options?: winston.LoggerOptions, env?: NodeJS.ProcessEnv, ): winston.Logger; +// Warning: (ae-forgotten-export) The symbol "ServiceBuilderImpl" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "createServiceBuilder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function createServiceBuilder(_module: NodeModule): ServiceBuilderImpl; +// Warning: (ae-forgotten-export) The symbol "StatusCheckRouterOptions" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "createStatusCheckRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function createStatusCheckRouter( options: StatusCheckRouterOptions, ): Promise; +// Warning: (ae-missing-release-tag) "DatabaseManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class DatabaseManager { + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen forPlugin(pluginId: string): PluginDatabaseManager; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static fromConfig(config: Config): DatabaseManager; } +// Warning: (ae-missing-release-tag) "DockerContainerRunner" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class DockerContainerRunner implements ContainerRunner { constructor({ dockerClient }: { dockerClient: Docker }); @@ -142,20 +187,27 @@ export class DockerContainerRunner implements ContainerRunner { mountDirs, workingDir, envVars, + pullImage, }: RunContainerOptions): Promise; } +// Warning: (ae-missing-release-tag) "ensureDatabaseExists" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function ensureDatabaseExists( dbConfig: Config, ...databases: Array ): Promise; +// Warning: (ae-missing-release-tag) "errorHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function errorHandler( options?: ErrorHandlerOptions, ): ErrorRequestHandler; +// Warning: (ae-missing-release-tag) "ErrorHandlerOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ErrorHandlerOptions = { showStackTraces?: boolean; @@ -163,12 +215,18 @@ export type ErrorHandlerOptions = { logClientErrors?: boolean; }; +// Warning: (ae-missing-release-tag) "getRootLogger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function getRootLogger(): winston.Logger; +// Warning: (ae-missing-release-tag) "getVoidLogger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function getVoidLogger(): winston.Logger; +// Warning: (ae-missing-release-tag) "Git" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class Git { // (undocumented) @@ -273,6 +331,8 @@ export class Git { resolveRef({ dir, ref }: { dir: string; ref: string }): Promise; } +// Warning: (ae-missing-release-tag) "GithubUrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class GithubUrlReader implements UrlReader { constructor( @@ -296,6 +356,8 @@ export class GithubUrlReader implements UrlReader { toString(): string; } +// Warning: (ae-missing-release-tag) "GitlabUrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class GitlabUrlReader implements UrlReader { constructor( @@ -320,28 +382,41 @@ export class GitlabUrlReader implements UrlReader { export { isChildPath }; +// Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "loadBackendConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function loadBackendConfig(options: Options): Promise; +// Warning: (ae-missing-release-tag) "notFoundHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function notFoundHandler(): RequestHandler; +// Warning: (ae-missing-release-tag) "PluginCacheManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type PluginCacheManager = { getClient: (options?: ClientOptions) => CacheClient; }; +// Warning: (ae-missing-release-tag) "PluginDatabaseManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export interface PluginDatabaseManager { getClient(): Promise; } +// Warning: (ae-missing-release-tag) "PluginEndpointDiscovery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type PluginEndpointDiscovery = { getBaseUrl(pluginId: string): Promise; getExternalBaseUrl(pluginId: string): Promise; }; +// Warning: (ae-missing-release-tag) "ReadTreeResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type ReadTreeResponse = { files(): Promise; @@ -350,21 +425,41 @@ export type ReadTreeResponse = { etag: string; }; +// Warning: (ae-missing-release-tag) "ReadTreeResponseFile" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type ReadTreeResponseFile = { path: string; content(): Promise; }; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "requestLoggingHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function requestLoggingHandler(logger?: Logger_2): RequestHandler; +// Warning: (ae-missing-release-tag) "RequestLoggingHandlerFactory" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type RequestLoggingHandlerFactory = ( + logger?: Logger_2, +) => RequestHandler; + +// Warning: (ae-missing-release-tag) "resolvePackagePath" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function resolvePackagePath(name: string, ...paths: string[]): string; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "resolveSafeChildPath" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function resolveSafeChildPath(base: string, path: string): string; +// Warning: (ae-missing-release-tag) "RunContainerOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type RunContainerOptions = { imageName: string; @@ -374,20 +469,27 @@ export type RunContainerOptions = { mountDirs?: Record; workingDir?: string; envVars?: Record; + pullImage?: boolean; }; +// Warning: (ae-missing-release-tag) "SearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type SearchResponse = { files: SearchResponseFile[]; etag: string; }; +// Warning: (ae-missing-release-tag) "SearchResponseFile" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type SearchResponseFile = { url: string; content(): Promise; }; +// Warning: (ae-missing-release-tag) "ServiceBuilder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ServiceBuilder = { loadConfig(config: ConfigReader): ServiceBuilder; @@ -397,15 +499,24 @@ export type ServiceBuilder = { enableCors(options: cors.CorsOptions): ServiceBuilder; setHttpsSettings(settings: HttpsSettings): ServiceBuilder; addRouter(root: string, router: Router | RequestHandler): ServiceBuilder; + setRequestLoggingHandler( + requestLoggingHandler: RequestLoggingHandlerFactory, + ): ServiceBuilder; start(): Promise; }; +// Warning: (ae-missing-release-tag) "setRootLogger" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function setRootLogger(newLogger: winston.Logger): void; +// Warning: (ae-missing-release-tag) "SingleConnectionDatabaseManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated export const SingleConnectionDatabaseManager: typeof DatabaseManager; +// Warning: (ae-missing-release-tag) "SingleHostDiscovery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class SingleHostDiscovery implements PluginEndpointDiscovery { static fromConfig( @@ -420,19 +531,28 @@ export class SingleHostDiscovery implements PluginEndpointDiscovery { getExternalBaseUrl(pluginId: string): Promise; } +// Warning: (ae-missing-release-tag) "StatusCheck" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type StatusCheck = () => Promise; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "statusCheckHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function statusCheckHandler( options?: StatusCheckHandlerOptions, ): Promise; +// Warning: (ae-missing-release-tag) "StatusCheckHandlerOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface StatusCheckHandlerOptions { statusCheck?: StatusCheck; } +// Warning: (ae-missing-release-tag) "UrlReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type UrlReader = { read(url: string): Promise; @@ -441,20 +561,49 @@ export type UrlReader = { search(url: string, options?: SearchOptions): Promise; }; +// Warning: (ae-missing-release-tag) "UrlReaders" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class UrlReaders { + // Warning: (ae-forgotten-export) The symbol "CreateOptions" needs to be exported by the entry point index.d.ts static create({ logger, config, factories }: CreateOptions): UrlReader; static default({ logger, config, factories }: CreateOptions): UrlReader; } +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "useHotCleanup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function useHotCleanup( _module: NodeModule, cancelEffect: () => void, ): void; +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@warning" is not defined in this configuration +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "useHotMemoize" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function useHotMemoize(_module: NodeModule, valueFactory: () => T): T; +// Warnings were encountered during analysis: +// +// src/cache/types.d.ts:34:5 - (ae-forgotten-export) The symbol "ClientOptions" needs to be exported by the entry point index.d.ts +// src/middleware/errorHandler.d.ts:17:26 - (tsdoc-malformed-html-name) Invalid HTML element: A space is not allowed here +// src/reading/AzureUrlReader.d.ts:9:9 - (ae-forgotten-export) The symbol "ReadTreeResponseFactory" needs to be exported by the entry point index.d.ts +// src/reading/types.d.ts:106:5 - (ae-forgotten-export) The symbol "ReadTreeResponseDirOptions" needs to be exported by the entry point index.d.ts +// src/service/types.d.ts:12:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:22:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:30:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:38:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:47:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:55:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:57:5 - (ae-forgotten-export) The symbol "HttpsSettings" needs to be exported by the entry point index.d.ts +// src/service/types.d.ts:61:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:62:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/service/types.d.ts:70:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 6cf20b8234..10602fa2fa 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.8.5", + "version": "0.8.8", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -30,10 +30,10 @@ }, "dependencies": { "@backstage/cli-common": "^0.1.2", - "@backstage/config": "^0.1.5", - "@backstage/config-loader": "^0.6.4", + "@backstage/config": "^0.1.6", + "@backstage/config-loader": "^0.6.6", "@backstage/errors": "^0.1.1", - "@backstage/integration": "^0.5.8", + "@backstage/integration": "^0.5.9", "@google-cloud/storage": "^5.8.0", "@octokit/rest": "^18.5.3", "@types/cors": "^2.8.6", @@ -62,7 +62,7 @@ "raw-body": "^2.4.1", "selfsigned": "^1.10.7", "stoppable": "^1.1.0", - "tar": "^6.0.5", + "tar": "^6.1.2", "unzipper": "^0.10.11", "winston": "^3.2.1", "yn": "^4.0.0" @@ -76,8 +76,8 @@ } }, "devDependencies": { - "@backstage/cli": "^0.7.3", - "@backstage/test-utils": "^0.1.12", + "@backstage/cli": "^0.7.7", + "@backstage/test-utils": "^0.1.15", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", "@types/concat-stream": "^1.6.0", diff --git a/packages/backend-common/src/reading/FetchUrlReader.test.ts b/packages/backend-common/src/reading/FetchUrlReader.test.ts index 169cbfbf66..e8c16c5f0a 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.test.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.test.ts @@ -15,12 +15,16 @@ */ import { ConfigReader } from '@backstage/config'; +import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { msw } from '@backstage/test-utils'; +import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { getVoidLogger } from '../logging'; import { FetchUrlReader } from './FetchUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; +const fetchUrlReader = new FetchUrlReader(); + describe('FetchUrlReader', () => { const worker = setupServer(); @@ -30,6 +34,39 @@ describe('FetchUrlReader', () => { jest.clearAllMocks(); }); + beforeEach(() => { + worker.use( + rest.get('https://backstage.io/some-resource', (req, res, ctx) => { + if (req.headers.get('if-none-match') === 'foo') { + return res( + ctx.status(304), + ctx.set('Content-Type', 'text/plain'), + ctx.set('etag', 'foo'), + ); + } + + return res( + ctx.status(200), + ctx.set('Content-Type', 'text/plain'), + ctx.set('etag', 'foo'), + ctx.body('content foo'), + ); + }), + ); + + worker.use( + rest.get('https://backstage.io/not-exists', (_req, res, ctx) => { + return res(ctx.status(404)); + }), + ); + + worker.use( + rest.get('https://backstage.io/error', (_req, res, ctx) => { + return res(ctx.status(500), ctx.body('An internal error occured')); + }), + ); + }); + it('factory should create a single entry with a predicate that matches config', async () => { const entries = FetchUrlReader.factory({ config: new ConfigReader({ @@ -70,4 +107,55 @@ describe('FetchUrlReader', () => { expect(predicate(new URL('https://a.examples.org:700/test'))).toBe(true); expect(predicate(new URL('https://a.b.examples.org:700/test'))).toBe(true); }); + + describe('read', () => { + it('should return etag from the response', async () => { + const buffer = await fetchUrlReader.read( + 'https://backstage.io/some-resource', + ); + expect(buffer.toString()).toBe('content foo'); + }); + + it('should throw NotFound if server responds with 404', async () => { + await expect( + fetchUrlReader.read('https://backstage.io/not-exists'), + ).rejects.toThrow(NotFoundError); + }); + + it('should throw Error if server responds with 500', async () => { + await expect( + fetchUrlReader.read('https://backstage.io/error'), + ).rejects.toThrow(Error); + }); + }); + + describe('readUrl', () => { + it('should throw NotModified if server responds with 304', async () => { + await expect( + fetchUrlReader.readUrl('https://backstage.io/some-resource', { + etag: 'foo', + }), + ).rejects.toThrow(NotModifiedError); + }); + + it('should return etag from the response', async () => { + const response = await fetchUrlReader.readUrl( + 'https://backstage.io/some-resource', + ); + expect(response.etag).toBe('foo'); + expect((await response.buffer()).toString()).toEqual('content foo'); + }); + + it('should throw NotFound if server responds with 404', async () => { + await expect( + fetchUrlReader.readUrl('https://backstage.io/not-exists'), + ).rejects.toThrow(NotFoundError); + }); + + it('should throw Error if server responds with 500', async () => { + await expect( + fetchUrlReader.readUrl('https://backstage.io/error'), + ).rejects.toThrow(Error); + }); + }); }); diff --git a/packages/backend-common/src/reading/FetchUrlReader.ts b/packages/backend-common/src/reading/FetchUrlReader.ts index 30468158aa..3177ee1f8e 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.ts @@ -14,8 +14,8 @@ * limitations under the License. */ +import { NotFoundError, NotModifiedError } from '@backstage/errors'; import fetch from 'cross-fetch'; -import { NotFoundError } from '@backstage/errors'; import { ReaderFactory, ReadTreeResponse, @@ -57,15 +57,34 @@ export class FetchUrlReader implements UrlReader { }; async read(url: string): Promise { + const response = await this.readUrl(url); + return response.buffer(); + } + + async readUrl( + url: string, + options?: ReadUrlOptions, + ): Promise { let response: Response; try { - response = await fetch(url); + response = await fetch(url, { + headers: { + ...(options?.etag && { 'If-None-Match': options.etag }), + }, + }); } catch (e) { throw new Error(`Unable to read ${url}, ${e}`); } + if (response.status === 304) { + throw new NotModifiedError(); + } + if (response.ok) { - return Buffer.from(await response.text()); + return { + buffer: async () => Buffer.from(await response.text()), + etag: response.headers.get('ETag') ?? undefined, + }; } const message = `could not read ${url}, ${response.status} ${response.statusText}`; @@ -75,15 +94,6 @@ export class FetchUrlReader implements UrlReader { throw new Error(message); } - async readUrl( - url: string, - _options?: ReadUrlOptions, - ): Promise { - // TODO etag is not implemented yet. - const buffer = await this.read(url); - return { buffer: async () => buffer }; - } - async readTree(): Promise { throw new Error('FetchUrlReader does not implement readTree'); } diff --git a/packages/backend-common/src/reading/UrlReaderPredicateMux.ts b/packages/backend-common/src/reading/UrlReaderPredicateMux.ts index 4a166cb517..bbe94a0fb4 100644 --- a/packages/backend-common/src/reading/UrlReaderPredicateMux.ts +++ b/packages/backend-common/src/reading/UrlReaderPredicateMux.ts @@ -52,7 +52,11 @@ export class UrlReaderPredicateMux implements UrlReader { } } - throw new NotAllowedError(`Reading from '${url}' is not allowed`); + throw new NotAllowedError( + `Reading from '${url}' is not allowed. ` + + `You may need to configure an integration for the target host, or add it ` + + `to the configured list of allowed hosts at 'backend.reading.allow'`, + ); } async readUrl( diff --git a/packages/backend-common/src/service/index.ts b/packages/backend-common/src/service/index.ts index 4eb0bf4a5a..d01f25fad3 100644 --- a/packages/backend-common/src/service/index.ts +++ b/packages/backend-common/src/service/index.ts @@ -16,4 +16,4 @@ export { createServiceBuilder } from './createServiceBuilder'; export { createStatusCheckRouter } from './createStatusCheckRouter'; -export type { ServiceBuilder } from './types'; +export type { ServiceBuilder, RequestLoggingHandlerFactory } from './types'; diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index 380d61abc8..7a3ebfed70 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -27,9 +27,9 @@ import { getRootLogger } from '../../logging'; import { errorHandler, notFoundHandler, - requestLoggingHandler, + requestLoggingHandler as defaultRequestLoggingHandler, } from '../../middleware'; -import { ServiceBuilder } from '../types'; +import { RequestLoggingHandlerFactory, ServiceBuilder } from '../types'; import { CspOptions, HttpsSettings, @@ -65,6 +65,7 @@ export class ServiceBuilderImpl implements ServiceBuilder { private cspOptions: Record | undefined; private httpsSettings: HttpsSettings | undefined; private routers: [string, Router][]; + private requestLoggingHandler: RequestLoggingHandlerFactory | undefined; // Reference to the module where builder is created - needed for hot module // reloading private module: NodeModule; @@ -144,6 +145,13 @@ export class ServiceBuilderImpl implements ServiceBuilder { return this; } + setRequestLoggingHandler( + requestLoggingHandler: RequestLoggingHandlerFactory, + ) { + this.requestLoggingHandler = requestLoggingHandler; + return this; + } + async start(): Promise { const app = express(); const { @@ -160,7 +168,9 @@ export class ServiceBuilderImpl implements ServiceBuilder { app.use(cors(corsOptions)); } app.use(compression()); - app.use(requestLoggingHandler(logger)); + app.use( + (this.requestLoggingHandler ?? defaultRequestLoggingHandler)(logger), + ); for (const [root, route] of this.routers) { app.use(root, route); } diff --git a/packages/backend-common/src/service/types.ts b/packages/backend-common/src/service/types.ts index 70f62acfca..f845397ca2 100644 --- a/packages/backend-common/src/service/types.ts +++ b/packages/backend-common/src/service/types.ts @@ -85,8 +85,21 @@ export type ServiceBuilder = { */ addRouter(root: string, router: Router | RequestHandler): ServiceBuilder; + /** + * Set the request logging handler + * + * If no handler is given the default one is used + * + * @param requestLoggingHandler a factory function that given a logger returns an handler + */ + setRequestLoggingHandler( + requestLoggingHandler: RequestLoggingHandlerFactory, + ): ServiceBuilder; + /** * Starts the server using the given settings. */ start(): Promise; }; + +export type RequestLoggingHandlerFactory = (logger?: Logger) => RequestHandler; diff --git a/packages/backend-common/src/util/ContainerRunner.ts b/packages/backend-common/src/util/ContainerRunner.ts index 80ac4e3954..8a73be42ba 100644 --- a/packages/backend-common/src/util/ContainerRunner.ts +++ b/packages/backend-common/src/util/ContainerRunner.ts @@ -24,6 +24,7 @@ export type RunContainerOptions = { mountDirs?: Record; workingDir?: string; envVars?: Record; + pullImage?: boolean; }; export interface ContainerRunner { diff --git a/packages/backend-common/src/util/DockerContainerRunner.test.ts b/packages/backend-common/src/util/DockerContainerRunner.test.ts index 0ed41d5cd3..8833e4518b 100644 --- a/packages/backend-common/src/util/DockerContainerRunner.test.ts +++ b/packages/backend-common/src/util/DockerContainerRunner.test.ts @@ -58,6 +58,7 @@ describe('DockerContainerRunner', () => { }); afterEach(() => { + jest.clearAllMocks(); mockFs.restore(); }); @@ -86,6 +87,17 @@ describe('DockerContainerRunner', () => { expect(mockDocker.run).toHaveBeenCalled(); }); + it('should not pull the docker container when pullImage is false', async () => { + await containerTaskApi.runContainer({ + imageName, + args, + pullImage: false, + }); + + expect(mockDocker.pull).not.toHaveBeenCalled(); + expect(mockDocker.run).toHaveBeenCalled(); + }); + it('should call the dockerClient run command with the correct arguments passed through', async () => { await containerTaskApi.runContainer({ imageName, diff --git a/packages/backend-common/src/util/DockerContainerRunner.ts b/packages/backend-common/src/util/DockerContainerRunner.ts index 6ec366eb94..8dbc5335c9 100644 --- a/packages/backend-common/src/util/DockerContainerRunner.ts +++ b/packages/backend-common/src/util/DockerContainerRunner.ts @@ -38,6 +38,7 @@ export class DockerContainerRunner implements ContainerRunner { mountDirs = {}, workingDir, envVars = {}, + pullImage = true, }: RunContainerOptions) { // Show a better error message when Docker is unavailable. try { @@ -48,15 +49,17 @@ export class DockerContainerRunner implements ContainerRunner { ); } - await new Promise((resolve, reject) => { - this.dockerClient.pull(imageName, {}, (err, stream) => { - if (err) return reject(err); - stream.pipe(logStream, { end: false }); - stream.on('end', () => resolve()); - stream.on('error', (error: Error) => reject(error)); - return undefined; + if (pullImage) { + await new Promise((resolve, reject) => { + this.dockerClient.pull(imageName, {}, (err, stream) => { + if (err) return reject(err); + stream.pipe(logStream, { end: false }); + stream.on('end', () => resolve()); + stream.on('error', (error: Error) => reject(error)); + return undefined; + }); }); - }); + } const userOptions: UserOptions = {}; if (process.getuid && process.getgid) { diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 184ed74978..411ecc7ddf 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -5,9 +5,13 @@ ```ts import { Knex } from 'knex'; +// Warning: (ae-missing-release-tag) "isDockerDisabledForTests" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function isDockerDisabledForTests(): boolean; +// Warning: (ae-missing-release-tag) "TestDatabaseId" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type TestDatabaseId = | 'POSTGRES_13' @@ -15,6 +19,8 @@ export type TestDatabaseId = | 'MYSQL_8' | 'SQLITE_3'; +// Warning: (ae-missing-release-tag) "TestDatabases" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class TestDatabases { static create(options?: { @@ -23,6 +29,7 @@ export class TestDatabases { }): TestDatabases; // (undocumented) eachSupportedId(): [TestDatabaseId][]; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen init(id: TestDatabaseId): Promise; // (undocumented) supports(id: TestDatabaseId): boolean; diff --git a/packages/backend-test-utils/src/database/TestDatabases.test.ts b/packages/backend-test-utils/src/database/TestDatabases.test.ts index 62612f3fcc..000e047c4d 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.test.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.test.ts @@ -71,7 +71,7 @@ describe('TestDatabases', () => { await input.insert({ x: 'y' }).into('a'); // Look for the mark - const database = 'backstage_plugin_db0'; + const database = input.client.config.connection.database; const output = knexFactory({ client: 'pg', connection: { host, port, user, password, database }, @@ -105,7 +105,7 @@ describe('TestDatabases', () => { await input.insert({ x: 'y' }).into('a'); // Look for the mark - const database = 'backstage_plugin_db0'; + const database = input.client.config.connection.database; const output = knexFactory({ client: 'pg', connection: { host, port, user, password, database }, @@ -139,7 +139,7 @@ describe('TestDatabases', () => { await input.insert({ x: 'y' }).into('a'); // Look for the mark - const database = 'backstage_plugin_db0'; + const database = input.client.config.connection.database; const output = knexFactory({ client: 'mysql2', connection: { host, port, user, password, database }, diff --git a/packages/backend-test-utils/src/database/TestDatabases.ts b/packages/backend-test-utils/src/database/TestDatabases.ts index c35202354d..329aec5e8a 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.ts @@ -16,6 +16,7 @@ import { DatabaseManager } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; +import { randomBytes } from 'crypto'; import { Knex } from 'knex'; import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; import { startMysqlContainer } from './startMysqlContainer'; @@ -34,7 +35,6 @@ import { export class TestDatabases { private readonly instanceById: Map; private readonly supportedIds: TestDatabaseId[]; - private lastDatabaseIndex: number; /** * Creates an empty `TestDatabases` instance, and sets up Jest to clean up @@ -99,7 +99,6 @@ export class TestDatabases { private constructor(supportedIds: TestDatabaseId[]) { this.instanceById = new Map(); this.supportedIds = supportedIds; - this.lastDatabaseIndex = 0; } supports(id: TestDatabaseId): boolean { @@ -142,7 +141,7 @@ export class TestDatabases { // Ensure that a unique logical database is created in the instance const connection = await instance.databaseManager - .forPlugin(String(`db${this.lastDatabaseIndex++}`)) + .forPlugin(`db${randomBytes(16).toString('hex')}`) .getClient(); instance.connections.push(connection); diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 47edc5107f..a3e08db6b3 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,36 @@ # example-backend +## 0.2.38 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.3.11 + - @backstage/catalog-client@0.3.17 + - @backstage/plugin-auth-backend@0.3.18 + - @backstage/plugin-jenkins-backend@0.1.2 + - @backstage/backend-common@0.8.7 + - @backstage/plugin-techdocs-backend@0.9.0 + - @backstage/plugin-scaffolder-backend@0.14.1 + +## 0.2.37 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.8.6 + - @backstage/plugin-scaffolder-backend@0.14.0 + - @backstage/plugin-catalog-backend@0.13.0 + - @backstage/plugin-auth-backend@0.3.17 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.3 + - @backstage/plugin-search-backend-node@0.4.0 + - @backstage/plugin-techdocs-backend@0.8.7 + - @backstage/plugin-app-backend@0.3.15 + - @backstage/plugin-kubernetes-backend@0.3.10 + - @backstage/plugin-rollbar-backend@0.1.13 + - example-app@0.2.37 + - @backstage/plugin-search-backend@0.2.3 + ## 0.2.36 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 4338f3e2b7..33221bde01 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.36", + "version": "0.2.38", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,32 +27,35 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.8.5", - "@backstage/catalog-client": "^0.3.16", + "@backstage/backend-common": "^0.8.7", + "@backstage/catalog-client": "^0.3.17", "@backstage/catalog-model": "^0.9.0", "@backstage/config": "^0.1.5", "@backstage/integration": "^0.5.8", - "@backstage/plugin-app-backend": "^0.3.13", - "@backstage/plugin-auth-backend": "^0.3.16", + "@backstage/plugin-app-backend": "^0.3.15", + "@backstage/plugin-auth-backend": "^0.3.18", "@backstage/plugin-badges-backend": "^0.1.8", - "@backstage/plugin-catalog-backend": "^0.12.0", + "@backstage/plugin-catalog-backend": "^0.13.0", "@backstage/plugin-code-coverage-backend": "^0.1.8", "@backstage/plugin-graphql-backend": "^0.1.8", - "@backstage/plugin-kubernetes-backend": "^0.3.9", + "@backstage/plugin-jenkins-backend": "^0.1.2", + "@backstage/plugin-kubernetes-backend": "^0.3.11", "@backstage/plugin-kafka-backend": "^0.2.8", "@backstage/plugin-proxy-backend": "^0.2.9", - "@backstage/plugin-rollbar-backend": "^0.1.11", - "@backstage/plugin-scaffolder-backend": "^0.13.0", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.1.2", - "@backstage/plugin-search-backend": "^0.2.2", - "@backstage/plugin-search-backend-node": "^0.3.0", - "@backstage/plugin-techdocs-backend": "^0.8.6", + "@backstage/plugin-rollbar-backend": "^0.1.13", + "@backstage/plugin-scaffolder-backend": "^0.14.1", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.1.3", + "@backstage/plugin-search-backend": "^0.2.3", + "@backstage/plugin-search-backend-node": "^0.4.0", + "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.1", + "@backstage/plugin-search-backend-module-pg": "^0.1.0", + "@backstage/plugin-techdocs-backend": "^0.9.0", "@backstage/plugin-todo-backend": "^0.1.8", "@gitbeaker/node": "^30.2.0", "@octokit/rest": "^18.5.3", "azure-devops-node-api": "^10.2.2", "dockerode": "^3.2.1", - "example-app": "^0.2.36", + "example-app": "^0.2.37", "express": "^4.17.1", "express-promise-router": "^4.1.0", "knex": "^0.95.1", @@ -62,7 +65,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.7.3", + "@backstage/cli": "^0.7.5", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 168f6aa2d9..aecb233581 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -50,6 +50,7 @@ import todo from './plugins/todo'; import graphql from './plugins/graphql'; import app from './plugins/app'; import badges from './plugins/badges'; +import jenkins from './plugins/jenkins'; import { PluginEnvironment } from './types'; function makeCreateEnv(config: Config) { @@ -101,6 +102,7 @@ async function main() { const graphqlEnv = useHotMemoize(module, () => createEnv('graphql')); const appEnv = useHotMemoize(module, () => createEnv('app')); const badgesEnv = useHotMemoize(module, () => createEnv('badges')); + const jenkinsEnv = useHotMemoize(module, () => createEnv('jenkins')); const apiRouter = Router(); apiRouter.use('/catalog', await catalog(catalogEnv)); @@ -116,6 +118,7 @@ async function main() { apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use('/graphql', await graphql(graphqlEnv)); apiRouter.use('/badges', await badges(badgesEnv)); + apiRouter.use('/jenkins', await jenkins(jenkinsEnv)); apiRouter.use(notFoundHandler()); const service = createServiceBuilder(module) diff --git a/packages/backend/src/plugins/jenkins.ts b/packages/backend/src/plugins/jenkins.ts new file mode 100644 index 0000000000..5420eb0df6 --- /dev/null +++ b/packages/backend/src/plugins/jenkins.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 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. + */ + +import { + createRouter, + DefaultJenkinsInfoProvider, +} from '@backstage/plugin-jenkins-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; +import { CatalogClient } from '@backstage/catalog-client'; + +export default async function createPlugin({ + logger, + config, + discovery, +}: PluginEnvironment): Promise { + const catalog = new CatalogClient({ discoveryApi: discovery }); + + return await createRouter({ + logger, + jenkinsInfoProvider: DefaultJenkinsInfoProvider.fromConfig({ + catalog, + config, + }), + }); +} diff --git a/packages/backend/src/plugins/search.ts b/packages/backend/src/plugins/search.ts index 4a1e415c74..3470110408 100644 --- a/packages/backend/src/plugins/search.ts +++ b/packages/backend/src/plugins/search.ts @@ -13,21 +13,55 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useHotCleanup } from '@backstage/backend-common'; +import { + PluginDatabaseManager, + useHotCleanup, +} from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend'; import { createRouter } from '@backstage/plugin-search-backend'; +import { ElasticSearchSearchEngine } from '@backstage/plugin-search-backend-module-elasticsearch'; +import { PgSearchEngine } from '@backstage/plugin-search-backend-module-pg'; import { IndexBuilder, LunrSearchEngine, + SearchEngine, } from '@backstage/plugin-search-backend-node'; +import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend'; +import { Logger } from 'winston'; import { PluginEnvironment } from '../types'; -import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend'; + +async function createSearchEngine({ + logger, + database, + config, +}: { + logger: Logger; + database: PluginDatabaseManager; + config: Config; +}): Promise { + if (config.has('search.elasticsearch')) { + return await ElasticSearchSearchEngine.fromConfig({ + logger, + config, + }); + } + + if (await PgSearchEngine.supported(database)) { + return await PgSearchEngine.from({ database }); + } + + return new LunrSearchEngine({ logger }); +} export default async function createPlugin({ logger, discovery, + config, + database, }: PluginEnvironment) { // Initialize a connection to a search engine. - const searchEngine = new LunrSearchEngine({ logger }); + const searchEngine = await createSearchEngine({ config, logger, database }); const indexBuilder = new IndexBuilder({ logger, searchEngine }); // Collators are responsible for gathering documents known to plugins. This @@ -37,6 +71,11 @@ export default async function createPlugin({ collator: new DefaultCatalogCollator({ discovery }), }); + indexBuilder.addCollator({ + defaultRefreshIntervalSeconds: 600, + collator: new DefaultTechDocsCollator({ discovery, logger }), + }); + // The scheduler controls when documents are gathered from collators and sent // to the search engine for indexing. const { scheduler } = await indexBuilder.build(); diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 70b79b961f..d04d1dc936 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/catalog-client +## 0.3.18 + +### Patch Changes + +- 11c370af2: Support filtering entities via property existence + +## 0.3.17 + +### Patch Changes + +- 71c936eb6: Export `CatalogRequestOptions` type + ## 0.3.16 ### Patch Changes diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index 2abdeb8c75..173af9aef3 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -7,6 +7,8 @@ import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; import { Location as Location_2 } from '@backstage/catalog-model'; +// Warning: (ae-missing-release-tag) "AddLocationRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AddLocationRequest = { type?: string; @@ -15,12 +17,21 @@ export type AddLocationRequest = { presence?: 'optional' | 'required'; }; +// Warning: (ae-missing-release-tag) "AddLocationResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AddLocationResponse = { location: Location_2; entities: Entity[]; }; +// Warning: (ae-missing-release-tag) "CATALOG_FILTER_EXISTS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const CATALOG_FILTER_EXISTS: unique symbol; + +// Warning: (ae-missing-release-tag) "CatalogApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface CatalogApi { // (undocumented) @@ -65,6 +76,8 @@ export interface CatalogApi { ): Promise; } +// Warning: (ae-missing-release-tag) "CatalogClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class CatalogClient implements CatalogApi { constructor(options: { discoveryApi: DiscoveryApi }); @@ -110,23 +123,40 @@ export class CatalogClient implements CatalogApi { ): Promise; } +// Warning: (ae-missing-release-tag) "CatalogEntitiesRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type CatalogEntitiesRequest = { filter?: - | Record[] - | Record + | Record[] + | Record | undefined; fields?: string[] | undefined; }; +// Warning: (ae-missing-release-tag) "CatalogListResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type CatalogListResponse = { items: T[]; }; +// Warning: (ae-missing-release-tag) "CatalogRequestOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type CatalogRequestOptions = { + token?: string; +}; + +// Warning: (ae-missing-release-tag) "ENTITY_STATUS_CATALOG_PROCESSING_TYPE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ENTITY_STATUS_CATALOG_PROCESSING_TYPE = 'backstage.io/catalog-processing'; +// Warnings were encountered during analysis: +// +// src/CatalogClient.d.ts:7:9 - (ae-forgotten-export) The symbol "DiscoveryApi" needs to be exported by the entry point index.d.ts + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index fbb37d2449..cdbee32305 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "0.3.16", + "version": "0.3.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.7.3", + "@backstage/cli": "^0.7.6", "@types/jest": "^26.0.7", "msw": "^0.29.0" }, diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index 4e3d95f99f..d2db98bb25 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -18,7 +18,7 @@ import { Entity } from '@backstage/catalog-model'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { CatalogClient } from './CatalogClient'; -import { CatalogListResponse } from './types/api'; +import { CATALOG_FILTER_EXISTS, CatalogListResponse } from './types/api'; import { DiscoveryApi } from './types/discovery'; const server = setupServer(); @@ -83,7 +83,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { expect(req.url.search).toBe( - '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2', + '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c', ); return res(ctx.json([])); }), @@ -100,6 +100,9 @@ describe('CatalogClient', () => { { a: '2', }, + { + c: CATALOG_FILTER_EXISTS, + }, ], }, { token }, @@ -113,7 +116,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D'); + expect(req.url.search).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D,c'); return res(ctx.json([])); }), ); @@ -124,6 +127,7 @@ describe('CatalogClient', () => { a: '1', b: ['2', '3'], ö: '=', + c: CATALOG_FILTER_EXISTS, }, }, { token }, diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index 5dfcddde0c..ef90287c37 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -26,6 +26,7 @@ import { import { ResponseError } from '@backstage/errors'; import fetch from 'cross-fetch'; import { + CATALOG_FILTER_EXISTS, AddLocationRequest, AddLocationResponse, CatalogApi, @@ -69,9 +70,13 @@ export class CatalogClient implements CatalogApi { const filterParts: string[] = []; for (const [key, value] of Object.entries(filterItem)) { for (const v of [value].flat()) { - filterParts.push( - `${encodeURIComponent(key)}=${encodeURIComponent(v)}`, - ); + if (v === CATALOG_FILTER_EXISTS) { + filterParts.push(encodeURIComponent(key)); + } else if (typeof v === 'string') { + filterParts.push( + `${encodeURIComponent(key)}=${encodeURIComponent(v)}`, + ); + } } } diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index ae3fd7b514..d30caa50d6 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -16,10 +16,12 @@ import { Entity, EntityName, Location } from '@backstage/catalog-model'; +export const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS'); + export type CatalogEntitiesRequest = { filter?: - | Record[] - | Record + | Record[] + | Record | undefined; fields?: string[] | undefined; }; diff --git a/packages/catalog-client/src/types/index.ts b/packages/catalog-client/src/types/index.ts index 842d0393a4..3bfcdd7fba 100644 --- a/packages/catalog-client/src/types/index.ts +++ b/packages/catalog-client/src/types/index.ts @@ -20,5 +20,7 @@ export type { CatalogApi, CatalogEntitiesRequest, CatalogListResponse, + CatalogRequestOptions, } from './api'; +export { CATALOG_FILTER_EXISTS } from './api'; export { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from './status'; diff --git a/packages/catalog-model/api-report.md b/packages/catalog-model/api-report.md index 74027716de..437a0be02b 100644 --- a/packages/catalog-model/api-report.md +++ b/packages/catalog-model/api-report.md @@ -9,6 +9,9 @@ import { JsonValue } from '@backstage/config'; import { SerializedError } from '@backstage/errors'; import * as yup from 'yup'; +// Warning: (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative +// Warning: (ae-missing-release-tag) "analyzeLocationSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated (undocumented) export const analyzeLocationSchema: yup.ObjectSchema< { @@ -17,6 +20,8 @@ export const analyzeLocationSchema: yup.ObjectSchema< object >; +// Warning: (ae-missing-release-tag) "ApiEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface ApiEntityV1alpha1 extends Entity { // (undocumented) @@ -35,24 +40,43 @@ interface ApiEntityV1alpha1 extends Entity { export { ApiEntityV1alpha1 as ApiEntity }; export { ApiEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "apiEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const apiEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "CommonValidatorFunctions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class CommonValidatorFunctions { + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isJsonSafe(value: unknown): boolean; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isValidDnsLabel(value: unknown): boolean; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isValidDnsSubdomain(value: unknown): boolean; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isValidPrefixAndOrSuffix( value: unknown, separator: string, isValidPrefix: (value: string) => boolean, isValidSuffix: (value: string) => boolean, ): boolean; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isValidString(value: unknown): boolean; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static isValidUrl(value: unknown): boolean; } +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-forgotten-export) The symbol "EntityRefContext" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "compareEntityToRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function compareEntityToRef( entity: Entity, @@ -60,6 +84,8 @@ export function compareEntityToRef( context?: EntityRefContext, ): boolean; +// Warning: (ae-missing-release-tag) "ComponentEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface ComponentEntityV1alpha1 extends Entity { // (undocumented) @@ -81,9 +107,13 @@ interface ComponentEntityV1alpha1 extends Entity { export { ComponentEntityV1alpha1 as ComponentEntity }; export { ComponentEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "componentEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const componentEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "DefaultNamespaceEntityPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class DefaultNamespaceEntityPolicy implements EntityPolicy { constructor(namespace?: string); @@ -91,6 +121,8 @@ export class DefaultNamespaceEntityPolicy implements EntityPolicy { enforce(entity: Entity): Promise; } +// Warning: (ae-missing-release-tag) "DomainEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface DomainEntityV1alpha1 extends Entity { // (undocumented) @@ -105,12 +137,18 @@ interface DomainEntityV1alpha1 extends Entity { export { DomainEntityV1alpha1 as DomainEntity }; export { DomainEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "domainEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const domainEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "EDIT_URL_ANNOTATION" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url'; +// Warning: (ae-missing-release-tag) "Entity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type Entity = { apiVersion: string; @@ -121,9 +159,13 @@ export type Entity = { status?: UNSTABLE_EntityStatus; }; +// Warning: (ae-missing-release-tag) "ENTITY_DEFAULT_NAMESPACE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ENTITY_DEFAULT_NAMESPACE = 'default'; +// Warning: (ae-missing-release-tag) "ENTITY_META_GENERATED_FIELDS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ENTITY_META_GENERATED_FIELDS: readonly [ 'uid', @@ -131,6 +173,8 @@ export const ENTITY_META_GENERATED_FIELDS: readonly [ 'generation', ]; +// Warning: (ae-missing-release-tag) "EntityEnvelope" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityEnvelope = { apiVersion: string; @@ -141,19 +185,35 @@ export type EntityEnvelope = { }; }; +// Warning: (ae-missing-release-tag) "entityEnvelopeSchemaValidator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/catalog-model" does not have an export "TypeError" +// // @public export function entityEnvelopeSchemaValidator< T extends EntityEnvelope = EntityEnvelope >(schema?: unknown): (data: unknown) => T; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "entityHasChanges" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function entityHasChanges(previous: Entity, next: Entity): boolean; +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (ae-missing-release-tag) "entityKindSchemaValidator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/catalog-model" does not have an export "TypeError" +// // @public export function entityKindSchemaValidator( schema: unknown, ): (data: unknown) => T | false; +// Warning: (ae-missing-release-tag) "EntityLink" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityLink = { url: string; @@ -161,6 +221,8 @@ export type EntityLink = { icon?: string; }; +// Warning: (ae-missing-release-tag) "EntityMeta" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityMeta = JsonObject & { uid?: string; @@ -175,6 +237,8 @@ export type EntityMeta = JsonObject & { links?: EntityLink[]; }; +// Warning: (ae-missing-release-tag) "EntityName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityName = { kind: string; @@ -182,17 +246,23 @@ export type EntityName = { name: string; }; +// Warning: (ae-missing-release-tag) "EntityPolicies" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const EntityPolicies: { allOf(policies: EntityPolicy[]): AllEntityPolicies; oneOf(policies: EntityPolicy[]): AnyEntityPolicy; }; +// Warning: (ae-missing-release-tag) "EntityPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityPolicy = { enforce(entity: Entity): Promise; }; +// Warning: (ae-missing-release-tag) "EntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityRef = | string @@ -202,12 +272,16 @@ export type EntityRef = name: string; }; +// Warning: (ae-missing-release-tag) "EntityRelation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityRelation = { type: string; target: EntityName; }; +// Warning: (ae-missing-release-tag) "EntityRelationSpec" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type EntityRelationSpec = { source: EntityName; @@ -215,11 +289,16 @@ export type EntityRelationSpec = { target: EntityName; }; +// Warning: (ae-missing-release-tag) "entitySchemaValidator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/catalog-model" does not have an export "TypeError" +// // @public export function entitySchemaValidator( schema?: unknown, ): (data: unknown) => T; +// Warning: (ae-missing-release-tag) "FieldFormatEntityPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class FieldFormatEntityPolicy implements EntityPolicy { constructor(validators?: Validators); @@ -227,18 +306,32 @@ export class FieldFormatEntityPolicy implements EntityPolicy { enforce(entity: Entity): Promise; } +// Warning: (ae-missing-release-tag) "generateEntityEtag" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function generateEntityEtag(): string; +// Warning: (ae-missing-release-tag) "generateEntityUid" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function generateEntityUid(): string; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "generateUpdatedEntity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function generateUpdatedEntity(previous: Entity, next: Entity): Entity; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "getEntityName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function getEntityName(entity: Entity): EntityName; +// Warning: (tsdoc-characters-after-block-tag) The token "@backstage" looks like a TSDoc tag but contains an invalid character "/"; if it is not a tag, use a backslash to escape the "@" +// Warning: (ae-missing-release-tag) "getEntitySourceLocation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function getEntitySourceLocation( entity: Entity, @@ -247,6 +340,8 @@ export function getEntitySourceLocation( target: string; }; +// Warning: (ae-missing-release-tag) "GroupEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface GroupEntityV1alpha1 extends Entity { // (undocumented) @@ -269,20 +364,28 @@ interface GroupEntityV1alpha1 extends Entity { export { GroupEntityV1alpha1 as GroupEntity }; export { GroupEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "groupEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const groupEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "JSONSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type JSONSchema = JSONSchema7 & { [key in string]?: JsonValue; }; +// Warning: (ae-missing-release-tag) "KindValidator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type KindValidator = { check(entity: Entity): Promise; }; +// Warning: (ae-missing-release-tag) "KubernetesValidatorFunctions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class KubernetesValidatorFunctions { // (undocumented) @@ -303,15 +406,21 @@ export class KubernetesValidatorFunctions { static isValidObjectName(value: unknown): boolean; } +// Warning: (ae-missing-release-tag) "Location" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type Location_2 = { id: string; } & LocationSpec; export { Location_2 as Location }; +// Warning: (ae-missing-release-tag) "LOCATION_ANNOTATION" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; +// Warning: (ae-missing-release-tag) "LocationEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface LocationEntityV1alpha1 extends Entity { // (undocumented) @@ -328,12 +437,19 @@ interface LocationEntityV1alpha1 extends Entity { export { LocationEntityV1alpha1 as LocationEntity }; export { LocationEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "locationEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const locationEntityV1alpha1Validator: KindValidator; +// Warning: (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative +// Warning: (ae-missing-release-tag) "locationSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated (undocumented) export const locationSchema: yup.ObjectSchema; +// Warning: (ae-missing-release-tag) "LocationSpec" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type LocationSpec = { type: string; @@ -341,12 +457,19 @@ export type LocationSpec = { presence?: 'optional' | 'required'; }; +// Warning: (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative +// Warning: (ae-missing-release-tag) "locationSpecSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated (undocumented) export const locationSpecSchema: yup.ObjectSchema; +// Warning: (ae-missing-release-tag) "makeValidator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function makeValidator(overrides?: Partial): Validators; +// Warning: (ae-missing-release-tag) "NoForeignRootFieldsEntityPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class NoForeignRootFieldsEntityPolicy implements EntityPolicy { constructor(knownFields?: string[]); @@ -354,16 +477,28 @@ export class NoForeignRootFieldsEntityPolicy implements EntityPolicy { enforce(entity: Entity): Promise; } +// Warning: (ae-missing-release-tag) "ORIGIN_LOCATION_ANNOTATION" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ORIGIN_LOCATION_ANNOTATION = 'backstage.io/managed-by-origin-location'; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "parseEntityName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function parseEntityName( ref: EntityRef, context?: EntityRefContext, ): EntityName; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "parseEntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "parseEntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "parseEntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function parseEntityRef( ref: EntityRef, @@ -401,6 +536,11 @@ export function parseEntityRef( name: string; }; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (ae-missing-release-tag) "parseLocationReference" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function parseLocationReference( ref: string, @@ -409,48 +549,78 @@ export function parseLocationReference( target: string; }; +// Warning: (ae-missing-release-tag) "RELATION_API_CONSUMED_BY" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_API_CONSUMED_BY = 'apiConsumedBy'; +// Warning: (ae-missing-release-tag) "RELATION_API_PROVIDED_BY" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_API_PROVIDED_BY = 'apiProvidedBy'; +// Warning: (ae-missing-release-tag) "RELATION_CHILD_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_CHILD_OF = 'childOf'; +// Warning: (ae-missing-release-tag) "RELATION_CONSUMES_API" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_CONSUMES_API = 'consumesApi'; +// Warning: (ae-missing-release-tag) "RELATION_DEPENDENCY_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_DEPENDENCY_OF = 'dependencyOf'; +// Warning: (ae-missing-release-tag) "RELATION_DEPENDS_ON" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_DEPENDS_ON = 'dependsOn'; +// Warning: (ae-missing-release-tag) "RELATION_HAS_MEMBER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_HAS_MEMBER = 'hasMember'; +// Warning: (ae-missing-release-tag) "RELATION_HAS_PART" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_HAS_PART = 'hasPart'; +// Warning: (ae-missing-release-tag) "RELATION_MEMBER_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_MEMBER_OF = 'memberOf'; +// Warning: (ae-missing-release-tag) "RELATION_OWNED_BY" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_OWNED_BY = 'ownedBy'; +// Warning: (ae-missing-release-tag) "RELATION_OWNER_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_OWNER_OF = 'ownerOf'; +// Warning: (ae-missing-release-tag) "RELATION_PARENT_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_PARENT_OF = 'parentOf'; +// Warning: (ae-missing-release-tag) "RELATION_PART_OF" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const RELATION_PART_OF = 'partOf'; +// Warning: (ae-missing-release-tag) "RELATION_PROVIDES_API" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RELATION_PROVIDES_API = 'providesApi'; +// Warning: (ae-missing-release-tag) "ResourceEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface ResourceEntityV1alpha1 extends Entity { // (undocumented) @@ -468,15 +638,22 @@ interface ResourceEntityV1alpha1 extends Entity { export { ResourceEntityV1alpha1 as ResourceEntity }; export { ResourceEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "resourceEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const resourceEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "SchemaValidEntityPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class SchemaValidEntityPolicy implements EntityPolicy { // (undocumented) enforce(entity: Entity): Promise; } +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "serializeEntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated export function serializeEntityRef( ref: @@ -488,9 +665,14 @@ export function serializeEntityRef( }, ): EntityRef; +// Warning: (ae-missing-release-tag) "SOURCE_LOCATION_ANNOTATION" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location'; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "stringifyEntityRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function stringifyEntityRef( ref: @@ -502,12 +684,19 @@ export function stringifyEntityRef( }, ): string; +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "stringifyLocationReference" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function stringifyLocationReference(ref: { type: string; target: string; }): string; +// Warning: (ae-missing-release-tag) "SystemEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface SystemEntityV1alpha1 extends Entity { // (undocumented) @@ -523,9 +712,13 @@ interface SystemEntityV1alpha1 extends Entity { export { SystemEntityV1alpha1 as SystemEntity }; export { SystemEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "systemEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const systemEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "TemplateEntityV1beta2" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface TemplateEntityV1beta2 extends Entity { // (undocumented) @@ -554,6 +747,8 @@ export interface TemplateEntityV1beta2 extends Entity { }; } +// Warning: (ae-missing-release-tag) "templateEntityV1beta2Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const templateEntityV1beta2Validator: KindValidator; @@ -573,6 +768,8 @@ export type UNSTABLE_EntityStatusItem = { // @alpha export type UNSTABLE_EntityStatusLevel = 'info' | 'warning' | 'error'; +// Warning: (ae-missing-release-tag) "UserEntityV1alpha1" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) interface UserEntityV1alpha1 extends Entity { // (undocumented) @@ -592,9 +789,13 @@ interface UserEntityV1alpha1 extends Entity { export { UserEntityV1alpha1 as UserEntity }; export { UserEntityV1alpha1 }; +// Warning: (ae-missing-release-tag) "userEntityV1alpha1Validator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const userEntityV1alpha1Validator: KindValidator; +// Warning: (ae-missing-release-tag) "Validators" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type Validators = { isValidApiVersion(value: unknown): boolean; @@ -608,8 +809,18 @@ export type Validators = { isValidTag(value: unknown): boolean; }; +// Warning: (ae-missing-release-tag) "VIEW_URL_ANNOTATION" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const VIEW_URL_ANNOTATION = 'backstage.io/view-url'; +// Warnings were encountered during analysis: +// +// src/EntityPolicies.d.ts:13:5 - (ae-forgotten-export) The symbol "AllEntityPolicies" needs to be exported by the entry point index.d.ts +// src/EntityPolicies.d.ts:14:5 - (ae-forgotten-export) The symbol "AnyEntityPolicy" needs to be exported by the entry point index.d.ts +// src/entity/Entity.d.ts:37:5 - (ae-incompatible-release-tags) The symbol "status" is marked as @public, but its signature references "UNSTABLE_EntityStatus" which is marked as @alpha +// src/entity/policies/types.d.ts:10:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/kinds/types.d.ts:9:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/cli-common/api-report.md b/packages/cli-common/api-report.md index 7141d27f3a..d6d1c4fc36 100644 --- a/packages/cli-common/api-report.md +++ b/packages/cli-common/api-report.md @@ -3,26 +3,33 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts - +// Warning: (ae-missing-release-tag) "findPaths" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function findPaths(searchDir: string): Paths; +// Warning: (ae-missing-release-tag) "isChildPath" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function isChildPath(base: string, path: string): boolean; +// Warning: (ae-missing-release-tag) "Paths" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type Paths = { - ownDir: string; - ownRoot: string; - targetDir: string; - targetRoot: string; - resolveOwn: ResolveFunc; - resolveOwnRoot: ResolveFunc; - resolveTarget: ResolveFunc; - resolveTargetRoot: ResolveFunc; + ownDir: string; + ownRoot: string; + targetDir: string; + targetRoot: string; + resolveOwn: ResolveFunc; + resolveOwnRoot: ResolveFunc; + resolveTarget: ResolveFunc; + resolveTargetRoot: ResolveFunc; }; +// Warnings were encountered during analysis: +// +// src/paths.d.ts:7:5 - (ae-forgotten-export) The symbol "ResolveFunc" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) - ``` diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index a8cacedf22..dc4512adee 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/cli +## 0.7.7 + +### Patch Changes + +- 6aa7c3db7: bump node-tar version to the latest +- e9d3983ee: Keep track of filtered configuration values when running frontend in development mode. +- Updated dependencies + - @backstage/config@0.1.6 + - @backstage/config-loader@0.6.6 + +## 0.7.6 + +### Patch Changes + +- 9d40fcb1e: - Bumping `material-ui/core` version to at least `4.12.2` as they made some breaking changes in later versions which broke `Pagination` of the `Table`. + - Switching out `material-table` to `@material-table/core` for support for the later versions of `material-ui/core` + - This causes a minor API change to `@backstage/core-components` as the interface for `Table` re-exports the `prop` from the underlying `Table` components. + - `onChangeRowsPerPage` has been renamed to `onRowsPerPageChange` + - `onChangePage` has been renamed to `onPageChange` + - Migration guide is here: https://material-table-core.com/docs/breaking-changes + +## 0.7.5 + +### Patch Changes + +- 9a96b5da7: chore: bump `eslint` to `7.30.0` + +## 0.7.4 + +### Patch Changes + +- ae84b20cf: Revert the upgrade to `fs-extra@10.0.0` as that seemed to have broken all installs inexplicably. +- Updated dependencies + - @backstage/config-loader@0.6.5 + ## 0.7.3 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index a7032879bc..48746ad87b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.7.3", + "version": "0.7.7", "private": false, "publishConfig": { "access": "public" @@ -31,8 +31,8 @@ "@babel/core": "^7.4.4", "@babel/plugin-transform-modules-commonjs": "^7.4.4", "@backstage/cli-common": "^0.1.2", - "@backstage/config": "^0.1.5", - "@backstage/config-loader": "^0.6.4", + "@backstage/config": "^0.1.6", + "@backstage/config-loader": "^0.6.6", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^4.0.0", "@lerna/project": "^4.0.0", @@ -53,8 +53,8 @@ "@types/start-server-webpack-plugin": "^2.2.0", "@types/webpack-env": "^1.15.2", "@types/webpack-node-externals": "^2.5.0", - "@typescript-eslint/eslint-plugin": "^v4.27.0", - "@typescript-eslint/parser": "^v4.27.0", + "@typescript-eslint/eslint-plugin": "^v4.28.3", + "@typescript-eslint/parser": "^v4.28.3", "@yarnpkg/lockfile": "^1.1.0", "babel-plugin-dynamic-import-node": "^2.3.3", "bfj": "^7.0.2", @@ -65,7 +65,7 @@ "dashify": "^2.0.0", "diff": "^5.0.0", "esbuild": "^0.8.56", - "eslint": "^7.1.0", + "eslint": "^7.30.0", "eslint-config-prettier": "^8.3.0", "eslint-formatter-friendly": "^7.0.0", "eslint-plugin-import": "^2.20.2", @@ -104,7 +104,7 @@ "start-server-webpack-plugin": "^2.2.5", "style-loader": "^1.2.1", "sucrase": "^3.18.2", - "tar": "^6.0.1", + "tar": "^6.1.2", "terser-webpack-plugin": "^1.4.3", "ts-loader": "^8.0.17", "typescript": "^4.0.3", @@ -118,14 +118,14 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.8.4", - "@backstage/config": "^0.1.5", - "@backstage/core-components": "^0.1.4", - "@backstage/core-plugin-api": "^0.1.3", - "@backstage/core-app-api": "^0.1.4", - "@backstage/dev-utils": "^0.2.0", - "@backstage/test-utils": "^0.1.14", - "@backstage/theme": "^0.2.8", + "@backstage/backend-common": "^0.8.8", + "@backstage/config": "^0.1.6", + "@backstage/core-components": "^0.3.0", + "@backstage/core-plugin-api": "^0.1.5", + "@backstage/core-app-api": "^0.1.7", + "@backstage/dev-utils": "^0.2.5", + "@backstage/test-utils": "^0.1.16", + "@backstage/theme": "^0.2.9", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts index 85fbdd97a0..208042c719 100644 --- a/packages/cli/src/commands/app/serve.ts +++ b/packages/cli/src/commands/app/serve.ts @@ -59,6 +59,7 @@ export default async (cmd: Command) => { ...(await loadCliConfig({ args: cmd.config, fromPackage: name, + withFilteredKeys: true, })), }); diff --git a/packages/cli/src/commands/plugin/serve.ts b/packages/cli/src/commands/plugin/serve.ts index b9ba93bc62..a0200b7ce8 100644 --- a/packages/cli/src/commands/plugin/serve.ts +++ b/packages/cli/src/commands/plugin/serve.ts @@ -28,6 +28,7 @@ export default async (cmd: Command) => { ...(await loadCliConfig({ args: cmd.config, fromPackage: name, + withFilteredKeys: true, })), }); diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index db96ca7686..a93f040122 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -22,6 +22,7 @@ type Options = { args: string[]; fromPackage?: string; mockEnv?: boolean; + withFilteredKeys?: boolean; }; export async function loadCliConfig(options: Options) { @@ -57,6 +58,7 @@ export async function loadCliConfig(options: Options) { try { const frontendAppConfigs = schema.process(appConfigs, { visibility: ['frontend'], + withFilteredKeys: options.withFilteredKeys, }); const frontendConfig = ConfigReader.fromConfigs(frontendAppConfigs); diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index dbba628055..fdac5a0c67 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -27,7 +27,7 @@ "@backstage/core-components": "^{{version '@backstage/core-components'}}", "@backstage/core-plugin-api": "^{{version '@backstage/core-plugin-api'}}", "@backstage/theme": "^{{version '@backstage/theme'}}", - "@material-ui/core": "^4.11.0", + "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index dc1f694dca..b709350a73 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/codemods +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.3.0 + - @backstage/core-plugin-api@0.1.5 + - @backstage/core-app-api@0.1.7 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.2.0 + - @backstage/core-app-api@0.1.6 + - @backstage/core-plugin-api@0.1.4 + +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.1.6 + - @backstage/core-app-api@0.1.5 + ## 0.1.5 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 9cf5730126..38602ca03d 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.5", + "version": "0.1.8", "private": false, "publishConfig": { "access": "public", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index e0be1eebc8..44819b6903 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/config-loader +## 0.6.6 + +### Patch Changes + +- e9d3983ee: Add option to populate the `filteredKeys` property when processing configuration with a schema. +- Updated dependencies + - @backstage/config@0.1.6 + +## 0.6.5 + +### Patch Changes + +- ae84b20cf: Revert the upgrade to `fs-extra@10.0.0` as that seemed to have broken all installs inexplicably. + ## 0.6.4 ### Patch Changes diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index ffd15b0c9a..47bc22c60f 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -7,6 +7,8 @@ import { AppConfig } from '@backstage/config'; import { JsonObject } from '@backstage/config'; import { JSONSchema7 } from 'json-schema'; +// Warning: (ae-missing-release-tag) "ConfigSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type ConfigSchema = { process( @@ -16,12 +18,19 @@ export type ConfigSchema = { serialize(): JsonObject; }; +// Warning: (ae-forgotten-export) The symbol "CONFIG_VISIBILITIES" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ConfigVisibility" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type ConfigVisibility = typeof CONFIG_VISIBILITIES[number]; +// Warning: (ae-missing-release-tag) "loadConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function loadConfig(options: LoadConfigOptions): Promise; +// Warning: (ae-missing-release-tag) "LoadConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type LoadConfigOptions = { configRoot: string; @@ -30,16 +39,28 @@ export type LoadConfigOptions = { experimentalEnvFunc?: EnvFunc; }; +// Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "loadConfigSchema" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function loadConfigSchema(options: Options): Promise; +// Warning: (ae-missing-release-tag) "mergeConfigSchemas" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function mergeConfigSchemas(schemas: JSONSchema7[]): JSONSchema7; +// Warning: (ae-missing-release-tag) "readEnvConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function readEnvConfig(env: { [name: string]: string | undefined; }): AppConfig[]; +// Warnings were encountered during analysis: +// +// src/lib/schema/types.d.ts:83:5 - (ae-forgotten-export) The symbol "ConfigProcessingOptions" needs to be exported by the entry point index.d.ts +// src/loader.d.ts:13:5 - (ae-forgotten-export) The symbol "EnvFunc" needs to be exported by the entry point index.d.ts + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index cff324484a..33b8acc3b9 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "0.6.4", + "version": "0.6.6", "private": false, "publishConfig": { "access": "public", @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/cli-common": "^0.1.1", - "@backstage/config": "^0.1.5", + "@backstage/config": "^0.1.6", "@types/json-schema": "^7.0.6", "ajv": "^7.0.3", "fs-extra": "9.1.0", diff --git a/packages/config-loader/src/lib/schema/filtering.test.ts b/packages/config-loader/src/lib/schema/filtering.test.ts index 5079afa876..d4b3cd55b6 100644 --- a/packages/config-loader/src/lib/schema/filtering.test.ts +++ b/packages/config-loader/src/lib/schema/filtering.test.ts @@ -63,43 +63,115 @@ const visibility = new Map( describe('filterByVisibility', () => { test.each<[ConfigVisibility[], JsonObject]>([ - [[], {}], + [ + [], + { + data: {}, + filteredKeys: [ + 'arr[0]', + 'arr[1]', + 'arr[2]', + 'objArr[0].f', + 'objArr[0].b', + 'objArr[0].s', + 'objArr[1].f', + 'objArr[1].b', + 'objArr[1].s', + 'obj.f', + 'obj.b.s', + 'arrF[0].never', + 'arrB[0].never', + 'arrS[0].never', + 'objF.never', + 'objB.never', + 'objS.never', + ], + }, + ], [ ['frontend'], { - arr: ['f'], - objArr: [{ f: 1 }, { f: 4 }], - obj: { f: 'a' }, - arrF: [], - objF: {}, + data: { + arr: ['f'], + objArr: [{ f: 1 }, { f: 4 }], + obj: { f: 'a' }, + arrF: [], + objF: {}, + }, + filteredKeys: [ + 'arr[1]', + 'arr[2]', + 'objArr[0].b', + 'objArr[0].s', + 'objArr[1].b', + 'objArr[1].s', + 'obj.b.s', + 'arrF[0].never', + 'arrB[0].never', + 'arrS[0].never', + 'objF.never', + 'objB.never', + 'objS.never', + ], }, ], [ ['backend'], { - arr: ['b'], - objArr: [{ b: 2 }, { b: 5 }], - obj: { b: {} }, - arrF: [{ never: 'here' }], - arrB: [{ never: 'here' }], - arrS: [{ never: 'here' }], - objF: { never: 'here' }, - objB: { never: 'here' }, - objS: { never: 'here' }, + data: { + arr: ['b'], + objArr: [{ b: 2 }, { b: 5 }], + obj: { b: {} }, + arrF: [{ never: 'here' }], + arrB: [{ never: 'here' }], + arrS: [{ never: 'here' }], + objF: { never: 'here' }, + objB: { never: 'here' }, + objS: { never: 'here' }, + }, + filteredKeys: [ + 'arr[0]', + 'arr[2]', + 'objArr[0].f', + 'objArr[0].s', + 'objArr[1].f', + 'objArr[1].s', + 'obj.f', + 'obj.b.s', + ], }, ], [ ['secret'], { - arr: ['s'], - objArr: [{ s: 3 }, { s: 6 }], - obj: { b: { s: true } }, - arrS: [], - objS: {}, + data: { + arr: ['s'], + objArr: [{ s: 3 }, { s: 6 }], + obj: { b: { s: true } }, + arrS: [], + objS: {}, + }, + filteredKeys: [ + 'arr[0]', + 'arr[1]', + 'objArr[0].f', + 'objArr[0].b', + 'objArr[1].f', + 'objArr[1].b', + 'obj.f', + 'arrF[0].never', + 'arrB[0].never', + 'arrS[0].never', + 'objF.never', + 'objB.never', + 'objS.never', + ], }, ], - [['frontend', 'backend', 'secret'], data], + [['frontend', 'backend', 'secret'], { data, filteredKeys: [] }], ])('should filter correctly with %p', (filter, expected) => { - expect(filterByVisibility(data, filter, visibility)).toEqual(expected); + expect( + filterByVisibility(data, filter, visibility, undefined, true), + ).toEqual(expected); }); }); diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts index 74d367a30a..3533be01b7 100644 --- a/packages/config-loader/src/lib/schema/filtering.ts +++ b/packages/config-loader/src/lib/schema/filtering.ts @@ -30,9 +30,17 @@ export function filterByVisibility( includeVisibilities: ConfigVisibility[], visibilityByPath: Map, transformFunc?: TransformFunc, -): JsonObject { - function transform(jsonVal: JsonValue, path: string): JsonValue | undefined { - const visibility = visibilityByPath.get(path) ?? DEFAULT_CONFIG_VISIBILITY; + withFilteredKeys?: boolean, +): { data: JsonObject; filteredKeys?: string[] } { + const filteredKeys = new Array(); + + function transform( + jsonVal: JsonValue, + visibilityPath: string, // Matches the format we get from ajv + filterPath: string, // Matches the format of the ConfigReader + ): JsonValue | undefined { + const visibility = + visibilityByPath.get(visibilityPath) ?? DEFAULT_CONFIG_VISIBILITY; const isVisible = includeVisibilities.includes(visibility); if (typeof jsonVal !== 'object') { @@ -42,6 +50,9 @@ export function filterByVisibility( } return jsonVal; } + if (withFilteredKeys) { + filteredKeys.push(filterPath); + } return undefined; } else if (jsonVal === null) { return undefined; @@ -49,7 +60,11 @@ export function filterByVisibility( const arr = new Array(); for (const [index, value] of jsonVal.entries()) { - const out = transform(value, `${path}/${index}`); + const out = transform( + value, + `${visibilityPath}/${index}`, + `${filterPath}[${index}]`, + ); if (out !== undefined) { arr.push(out); } @@ -68,7 +83,11 @@ export function filterByVisibility( if (value === undefined) { continue; } - const out = transform(value, `${path}/${key}`); + const out = transform( + value, + `${visibilityPath}/${key}`, + filterPath ? `${filterPath}.${key}` : key, + ); if (out !== undefined) { outObj[key] = out; hasOutput = true; @@ -81,5 +100,8 @@ export function filterByVisibility( return undefined; } - return (transform(data, '') as JsonObject) ?? {}; + return { + filteredKeys: withFilteredKeys ? filteredKeys : undefined, + data: (transform(data, '', '') as JsonObject) ?? {}, + }; } diff --git a/packages/config-loader/src/lib/schema/load.test.ts b/packages/config-loader/src/lib/schema/load.test.ts index 4a2b719590..73fa55b90c 100644 --- a/packages/config-loader/src/lib/schema/load.test.ts +++ b/packages/config-loader/src/lib/schema/load.test.ts @@ -68,13 +68,19 @@ describe('loadConfigSchema', () => { schema.process(configs, { visibility: ['frontend'], valueTransform: () => 'X', + withFilteredKeys: true, }), - ).toEqual([{ data: { key1: 'X' }, context: 'test' }]); + ).toEqual([ + { data: { key1: 'X' }, context: 'test', filteredKeys: ['key2'] }, + ]); expect( schema.process(configs, { valueTransform: () => 'X', + withFilteredKeys: true, }), - ).toEqual([{ data: { key1: 'X', key2: 'X' }, context: 'test' }]); + ).toEqual([ + { data: { key1: 'X', key2: 'X' }, context: 'test', filteredKeys: [] }, + ]); const serialized = schema.serialize(); diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts index ae5823c8cc..b67bd0002f 100644 --- a/packages/config-loader/src/lib/schema/load.ts +++ b/packages/config-loader/src/lib/schema/load.ts @@ -57,7 +57,7 @@ export async function loadConfigSchema( return { process( configs: AppConfig[], - { visibility, valueTransform } = {}, + { visibility, valueTransform, withFilteredKeys } = {}, ): AppConfig[] { const result = validate(configs); if (result.errors) { @@ -73,21 +73,23 @@ export async function loadConfigSchema( if (visibility) { processedConfigs = processedConfigs.map(({ data, context }) => ({ context, - data: filterByVisibility( + ...filterByVisibility( data, visibility, result.visibilityByPath, valueTransform, + withFilteredKeys, ), })); } else if (valueTransform) { processedConfigs = processedConfigs.map(({ data, context }) => ({ context, - data: filterByVisibility( + ...filterByVisibility( data, Array.from(CONFIG_VISIBILITIES), result.visibilityByPath, valueTransform, + withFilteredKeys, ), })); } diff --git a/packages/config-loader/src/lib/schema/types.ts b/packages/config-loader/src/lib/schema/types.ts index 30e47917bc..17090ad53c 100644 --- a/packages/config-loader/src/lib/schema/types.ts +++ b/packages/config-loader/src/lib/schema/types.ts @@ -96,6 +96,13 @@ type ConfigProcessingOptions = { * will be omitted. */ valueTransform?: TransformFunc; + + /** + * Whether or not to include the `filteredKeys` property in the output `AppConfig`s. + * + * Default: `false`. + */ + withFilteredKeys?: boolean; }; /** diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index 5cababf94e..63aa34b034 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/config +## 0.1.6 + +### Patch Changes + +- e9d3983ee: Add warning when trying to access configuration values that have been filtered out by visibility. + ## 0.1.5 ### Patch Changes diff --git a/packages/config/api-report.md b/packages/config/api-report.md index 0c243aab48..eff4236026 100644 --- a/packages/config/api-report.md +++ b/packages/config/api-report.md @@ -3,12 +3,17 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +// Warning: (ae-missing-release-tag) "AppConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AppConfig = { context: string; data: JsonObject; + filteredKeys?: string[]; }; +// Warning: (ae-missing-release-tag) "Config" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type Config = { has(key: string): boolean; @@ -29,6 +34,8 @@ export type Config = { getOptionalStringArray(key: string): string[] | undefined; }; +// Warning: (ae-missing-release-tag) "ConfigReader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class ConfigReader implements Config { constructor( @@ -73,17 +80,25 @@ export class ConfigReader implements Config { keys(): string[]; } +// Warning: (ae-missing-release-tag) "JsonArray" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface JsonArray extends Array {} +// Warning: (ae-missing-release-tag) "JsonObject" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type JsonObject = { [key in string]?: JsonValue; }; +// Warning: (ae-missing-release-tag) "JsonPrimitive" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type JsonPrimitive = number | string | boolean | null; +// Warning: (ae-missing-release-tag) "JsonValue" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type JsonValue = JsonObject | JsonArray | JsonPrimitive; diff --git a/packages/config/package.json b/packages/config/package.json index 400e4548cd..5d9bf94446 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "0.1.5", + "version": "0.1.6", "private": false, "publishConfig": { "access": "public", diff --git a/packages/config/src/reader.test.ts b/packages/config/src/reader.test.ts index b1ba536797..ed0ca7febe 100644 --- a/packages/config/src/reader.test.ts +++ b/packages/config/src/reader.test.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { withLogCollector } from '../../test-utils-core/src'; import { ConfigReader } from './reader'; const DATA = { @@ -185,6 +186,61 @@ describe('ConfigReader', () => { const config = new ConfigReader(DATA, CTX); expectInvalidValues(config); }); + + it('should warn when accessing filtered keys in development mode', () => { + const oldEnv = process.env.NODE_ENV; + (process.env as any).NODE_ENV = 'development'; + + const config = ConfigReader.fromConfigs([ + { + data: DATA, + context: CTX, + filteredKeys: ['a', 'b[0]'], + }, + ]); + + expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({ + warn: [ + "Failed to read configuration value at 'a' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.", + ], + }); + expect(withLogCollector(() => config.getOptionalString('a'))).toMatchObject( + { + warn: [ + "Failed to read configuration value at 'a' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.", + ], + }, + ); + expect( + withLogCollector(() => config.getOptionalConfigArray('b')), + ).toMatchObject({ + warn: [ + "Failed to read configuration array at 'b' as it does not have any visible elements. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.", + ], + }); + + (process.env as any).NODE_ENV = oldEnv; + }); + + it('should not warn when accessing filtered keys outside of development mode', () => { + const config = ConfigReader.fromConfigs([ + { + data: DATA, + context: CTX, + filteredKeys: ['a', 'b[0]'], + }, + ]); + + expect(withLogCollector(() => config.getOptional('a'))).toMatchObject({ + warn: [], + }); + expect( + withLogCollector(() => config.getOptionalString('a')), + ).toMatchObject({ warn: [] }); + expect( + withLogCollector(() => config.getOptionalConfigArray('b')), + ).toMatchObject({ warn: [] }); + }); }); describe('ConfigReader with fallback', () => { diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts index 11346d4a50..d93706c12e 100644 --- a/packages/config/src/reader.ts +++ b/packages/config/src/reader.ts @@ -55,6 +55,15 @@ const errors = { }; export class ConfigReader implements Config { + /** + * A set of key paths that where removed from the config due to not being visible. + * + * This was added as a mutable private member to avoid changes to the public API. + * Its only purpose of this is to warn users of missing visibility when running + * the frontend in development mode. + */ + private filteredKeys?: string[]; + static fromConfigs(configs: AppConfig[]): ConfigReader { if (configs.length === 0) { return new ConfigReader(undefined); @@ -62,9 +71,14 @@ export class ConfigReader implements Config { // Merge together all configs into a single config with recursive fallback // readers, giving the first config object in the array the lowest priority. - return configs.reduce((previousReader, { data, context }) => { - return new ConfigReader(data, context, previousReader); - }, undefined!); + return configs.reduce( + (previousReader, { data, context, filteredKeys }) => { + const reader = new ConfigReader(data, context, previousReader); + reader.filteredKeys = filteredKeys; + return reader; + }, + undefined!, + ); } constructor( @@ -101,6 +115,18 @@ export class ConfigReader implements Config { const fallbackValue = this.fallback?.getOptional(key); if (value === undefined) { + if (process.env.NODE_ENV === 'development') { + if (fallbackValue === undefined && key) { + const fullKey = this.fullKey(key); + if (this.filteredKeys?.includes(fullKey)) { + // eslint-disable-next-line no-console + console.warn( + `Failed to read configuration value at '${fullKey}' as it is not visible. ` + + 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.', + ); + } + } + } return fallbackValue; } else if (fallbackValue === undefined) { return value as T; @@ -127,10 +153,9 @@ export class ConfigReader implements Config { getOptionalConfig(key: string): ConfigReader | undefined { const value = this.readValue(key); const fallbackConfig = this.fallback?.getOptionalConfig(key); - const prefix = this.fullKey(key); if (isObject(value)) { - return new ConfigReader(value, this.context, fallbackConfig, prefix); + return this.copy(value, key, fallbackConfig); } if (value !== undefined) { throw new TypeError( @@ -163,18 +188,20 @@ export class ConfigReader implements Config { }); if (!configs) { + if (process.env.NODE_ENV === 'development') { + const fullKey = this.fullKey(key); + if (this.filteredKeys?.some(k => k.startsWith(fullKey))) { + // eslint-disable-next-line no-console + console.warn( + `Failed to read configuration array at '${key}' as it does not have any visible elements. ` + + 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.', + ); + } + } return undefined; } - return configs.map( - (obj, index) => - new ConfigReader( - obj, - this.context, - undefined, - this.fullKey(`${key}[${index}]`), - ), - ); + return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`)); } getNumber(key: string): number { @@ -261,6 +288,17 @@ export class ConfigReader implements Config { return `${this.prefix}${this.prefix ? '.' : ''}${key}`; } + private copy(data: JsonObject, key: string, fallback?: ConfigReader) { + const reader = new ConfigReader( + data, + this.context, + fallback, + this.fullKey(key), + ); + reader.filteredKeys = this.filteredKeys; + return reader; + } + private readConfigValue( key: string, validate: ( @@ -270,6 +308,17 @@ export class ConfigReader implements Config { const value = this.readValue(key); if (value === undefined) { + if (process.env.NODE_ENV === 'development') { + const fullKey = this.fullKey(key); + if (this.filteredKeys?.includes(fullKey)) { + // eslint-disable-next-line no-console + console.warn( + `Failed to read configuration value at '${fullKey}' as it is not visible. ` + + 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.', + ); + } + } + return this.fallback?.readConfigValue(key, validate); } const result = validate(value); diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts index d8f12f4f6e..1135e7d554 100644 --- a/packages/config/src/types.ts +++ b/packages/config/src/types.ts @@ -22,6 +22,7 @@ export type JsonValue = JsonObject | JsonArray | JsonPrimitive; export type AppConfig = { context: string; data: JsonObject; + filteredKeys?: string[]; }; export type Config = { diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 4f09f231c3..dbb26fe2a0 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/core-app-api +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.3.0 + - @backstage/config@0.1.6 + - @backstage/core-plugin-api@0.1.5 + +## 0.1.6 + +### Patch Changes + +- 9d40fcb1e: - Bumping `material-ui/core` version to at least `4.12.2` as they made some breaking changes in later versions which broke `Pagination` of the `Table`. + - Switching out `material-table` to `@material-table/core` for support for the later versions of `material-ui/core` + - This causes a minor API change to `@backstage/core-components` as the interface for `Table` re-exports the `prop` from the underlying `Table` components. + - `onChangeRowsPerPage` has been renamed to `onRowsPerPageChange` + - `onChangePage` has been renamed to `onPageChange` + - Migration guide is here: https://material-table-core.com/docs/breaking-changes +- Updated dependencies + - @backstage/core-components@0.2.0 + - @backstage/core-plugin-api@0.1.4 + - @backstage/theme@0.2.9 + +## 0.1.5 + +### Patch Changes + +- ea249c6e6: Fix a bug in `FlatRoutes` that prevented outlets from working with the root route, as well as matching root routes too broadly. +- Updated dependencies + - @backstage/core-components@0.1.6 + ## 0.1.4 ### Patch Changes diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index af86f042a0..a7a3845dd7 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -54,6 +54,8 @@ import { StorageApi } from '@backstage/core-plugin-api'; import { StorageValueChange } from '@backstage/core-plugin-api'; import { SubRouteRef } from '@backstage/core-plugin-api'; +// Warning: (ae-missing-release-tag) "AlertApiForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class AlertApiForwarder implements AlertApi { // (undocumented) @@ -62,6 +64,8 @@ export class AlertApiForwarder implements AlertApi { post(alert: AlertMessage): void; } +// Warning: (ae-missing-release-tag) "ApiFactoryHolder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ApiFactoryHolder = { get( @@ -77,6 +81,8 @@ export type ApiFactoryHolder = { | undefined; }; +// Warning: (ae-missing-release-tag) "ApiFactoryRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class ApiFactoryRegistry implements ApiFactoryHolder { // (undocumented) @@ -93,6 +99,7 @@ export class ApiFactoryRegistry implements ApiFactoryHolder { | undefined; // (undocumented) getAllApis(): Set; + // Warning: (ae-forgotten-export) The symbol "ApiFactoryScope" needs to be exported by the entry point index.d.ts register< Api, Impl extends Api, @@ -102,6 +109,8 @@ export class ApiFactoryRegistry implements ApiFactoryHolder { >(scope: ApiFactoryScope, factory: ApiFactory): boolean; } +// Warning: (ae-missing-release-tag) "ApiProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ApiProvider: { ({ apis, children }: PropsWithChildren): JSX.Element; @@ -115,19 +124,31 @@ export const ApiProvider: { }; }; +// Warning: (ae-missing-release-tag) "ApiRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class ApiRegistry implements ApiHolder { constructor(apis: Map); + // Warning: (ae-forgotten-export) The symbol "ApiRegistryBuilder" needs to be exported by the entry point index.d.ts + // // (undocumented) static builder(): ApiRegistryBuilder; + // Warning: (ae-forgotten-export) The symbol "ApiImpl" needs to be exported by the entry point index.d.ts + // // (undocumented) static from(apis: ApiImpl[]): ApiRegistry; // (undocumented) get(api: ApiRef): T | undefined; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen static with(api: ApiRef, impl: T): ApiRegistry; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen with(api: ApiRef, impl: T): ApiRegistry; } +// Warning: (ae-missing-release-tag) "ApiResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class ApiResolver implements ApiHolder { constructor(factories: ApiFactoryHolder); @@ -139,6 +160,8 @@ export class ApiResolver implements ApiHolder { ): void; } +// Warning: (ae-missing-release-tag) "AppComponents" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AppComponents = { NotFoundErrorPage: ComponentType<{}>; @@ -149,9 +172,13 @@ export type AppComponents = { SignInPage?: ComponentType; }; +// Warning: (ae-missing-release-tag) "AppConfigLoader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export type AppConfigLoader = () => Promise; +// Warning: (ae-missing-release-tag) "AppContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AppContext = { getPlugins(): BackstagePlugin[]; @@ -159,6 +186,8 @@ export type AppContext = { getComponents(): AppComponents; }; +// Warning: (ae-missing-release-tag) "AppOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AppOptions = { apis?: Iterable; @@ -173,6 +202,11 @@ export type AppOptions = { bindRoutes?(context: { bind: AppRouteBinder }): void; }; +// Warning: (ae-forgotten-export) The symbol "PartialKeys" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "TargetRouteMap" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "KeysWithType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "AppRouteBinder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type AppRouteBinder = < ExternalRoutes extends { @@ -186,6 +220,8 @@ export type AppRouteBinder = < >, ) => void; +// Warning: (ae-missing-release-tag) "AppThemeSelector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class AppThemeSelector implements AppThemeApi { constructor(themes: AppTheme[]); @@ -201,8 +237,12 @@ export class AppThemeSelector implements AppThemeApi { setActiveThemeId(themeId?: string): void; } +// Warning: (ae-missing-release-tag) "Auth0Auth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class Auth0Auth { + // Warning: (ae-forgotten-export) The symbol "OAuthApiCreateOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) static create({ discoveryApi, @@ -213,6 +253,8 @@ export class Auth0Auth { }: OAuthApiCreateOptions): typeof auth0AuthApiRef.T; } +// Warning: (ae-missing-release-tag) "BackstageApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type BackstageApp = { getPlugins(): BackstagePlugin[]; @@ -221,6 +263,8 @@ export type BackstageApp = { getRouter(): ComponentType<{}>; }; +// Warning: (ae-missing-release-tag) "BackstagePluginWithAnyOutput" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type BackstagePluginWithAnyOutput = Omit< BackstagePlugin, @@ -229,6 +273,8 @@ export type BackstagePluginWithAnyOutput = Omit< output(): (PluginOutput | UnknownPluginOutput)[]; }; +// Warning: (ae-missing-release-tag) "BootErrorPageProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type BootErrorPageProps = { step: 'load-config' | 'load-chunk'; @@ -237,12 +283,19 @@ export type BootErrorPageProps = { export { ConfigReader }; +// Warning: (ae-forgotten-export) The symbol "PrivateAppImpl" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "createApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export function createApp(options?: AppOptions): PrivateAppImpl; +// Warning: (ae-missing-release-tag) "defaultConfigLoader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const defaultConfigLoader: AppConfigLoader; +// Warning: (ae-missing-release-tag) "ErrorAlerter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class ErrorAlerter implements ErrorApi { constructor(alertApi: AlertApi, errorApi: ErrorApi); @@ -259,6 +312,8 @@ export class ErrorAlerter implements ErrorApi { post(error: Error, context?: ErrorContext): void; } +// Warning: (ae-missing-release-tag) "ErrorApiForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class ErrorApiForwarder implements ErrorApi { // (undocumented) @@ -270,6 +325,8 @@ export class ErrorApiForwarder implements ErrorApi { post(error: Error, context?: ErrorContext): void; } +// Warning: (ae-missing-release-tag) "ErrorBoundaryFallbackProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ErrorBoundaryFallbackProps = { plugin?: BackstagePlugin; @@ -277,9 +334,13 @@ export type ErrorBoundaryFallbackProps = { resetError: () => void; }; +// Warning: (ae-missing-release-tag) "FeatureFlagged" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const FeatureFlagged: (props: FeatureFlaggedProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "FeatureFlaggedProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type FeatureFlaggedProps = { children: ReactNode; @@ -292,11 +353,17 @@ export type FeatureFlaggedProps = { } ); +// Warning: (ae-forgotten-export) The symbol "FlatRoutesProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "FlatRoutes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const FlatRoutes: (props: FlatRoutesProps) => JSX.Element | null; +// Warning: (ae-missing-release-tag) "GithubAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class GithubAuth implements OAuthApi, SessionApi { + // Warning: (ae-forgotten-export) The symbol "SessionManager" needs to be exported by the entry point index.d.ts constructor(sessionManager: SessionManager); // (undocumented) static create({ @@ -324,6 +391,8 @@ export class GithubAuth implements OAuthApi, SessionApi { signOut(): Promise; } +// Warning: (ae-missing-release-tag) "GithubSession" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type GithubSession = { providerInfo: { @@ -335,6 +404,8 @@ export type GithubSession = { backstageIdentity: BackstageIdentity; }; +// Warning: (ae-missing-release-tag) "GitlabAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class GitlabAuth { // (undocumented) @@ -347,6 +418,8 @@ export class GitlabAuth { }: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T; } +// Warning: (ae-missing-release-tag) "GoogleAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class GoogleAuth { // (undocumented) @@ -359,6 +432,8 @@ export class GoogleAuth { }: OAuthApiCreateOptions): typeof googleAuthApiRef.T; } +// Warning: (ae-missing-release-tag) "LocalStorageFeatureFlags" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class LocalStorageFeatureFlags implements FeatureFlagsApi { // (undocumented) @@ -371,6 +446,8 @@ export class LocalStorageFeatureFlags implements FeatureFlagsApi { save(options: FeatureFlagsSaveOptions): void; } +// Warning: (ae-missing-release-tag) "MicrosoftAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class MicrosoftAuth { // (undocumented) @@ -383,6 +460,8 @@ export class MicrosoftAuth { }: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T; } +// Warning: (ae-missing-release-tag) "OAuth2" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class OAuth2 implements @@ -391,7 +470,10 @@ export class OAuth2 ProfileInfoApi, BackstageIdentityApi, SessionApi { + // Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts constructor(options: Options); + // Warning: (ae-forgotten-export) The symbol "CreateOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) static create({ discoveryApi, @@ -422,6 +504,8 @@ export class OAuth2 signOut(): Promise; } +// Warning: (ae-missing-release-tag) "OAuth2Session" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type OAuth2Session = { providerInfo: { @@ -434,6 +518,8 @@ export type OAuth2Session = { backstageIdentity: BackstageIdentity; }; +// Warning: (ae-missing-release-tag) "OAuthRequestManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class OAuthRequestManager implements OAuthRequestApi { // (undocumented) @@ -442,6 +528,8 @@ export class OAuthRequestManager implements OAuthRequestApi { createAuthRequester(options: AuthRequesterOptions): AuthRequester; } +// Warning: (ae-missing-release-tag) "OktaAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class OktaAuth { // (undocumented) @@ -454,8 +542,12 @@ export class OktaAuth { }: OAuthApiCreateOptions): typeof oktaAuthApiRef.T; } +// Warning: (ae-missing-release-tag) "OneLoginAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class OneLoginAuth { + // Warning: (ae-forgotten-export) The symbol "CreateOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) static create({ discoveryApi, @@ -465,10 +557,15 @@ export class OneLoginAuth { }: CreateOptions_2): typeof oneloginAuthApiRef.T; } +// Warning: (ae-missing-release-tag) "SamlAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class SamlAuth implements ProfileInfoApi, BackstageIdentityApi, SessionApi { + // Warning: (ae-forgotten-export) The symbol "SamlSession" needs to be exported by the entry point index.d.ts constructor(sessionManager: SessionManager); + // Warning: (ae-forgotten-export) The symbol "AuthApiCreateOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) static create({ discoveryApi, @@ -489,11 +586,15 @@ export class SamlAuth signOut(): Promise; } +// Warning: (ae-missing-release-tag) "SignInPageProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SignInPageProps = { onResult(result: SignInResult): void; }; +// Warning: (ae-missing-release-tag) "SignInResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SignInResult = { userId: string; @@ -502,11 +603,15 @@ export type SignInResult = { signOut?: () => Promise; }; +// Warning: (ae-missing-release-tag) "UnhandledErrorForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class UnhandledErrorForwarder { static forward(errorApi: ErrorApi, errorContext: ErrorContext): void; } +// Warning: (ae-missing-release-tag) "UrlPatternDiscovery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export class UrlPatternDiscovery implements DiscoveryApi { static compile(pattern: string): UrlPatternDiscovery; @@ -514,9 +619,13 @@ export class UrlPatternDiscovery implements DiscoveryApi { getBaseUrl(pluginId: string): Promise; } +// Warning: (ae-missing-release-tag) "WebStorage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export class WebStorage implements StorageApi { constructor(namespace: string, errorApi: ErrorApi); + // Warning: (ae-forgotten-export) The symbol "CreateStorageApiOptions" needs to be exported by the entry point index.d.ts + // // (undocumented) static create(options: CreateStorageApiOptions): WebStorage; // (undocumented) @@ -531,5 +640,11 @@ export class WebStorage implements StorageApi { set(key: string, data: T): Promise; } +// Warnings were encountered during analysis: +// +// src/apis/system/ApiProvider.d.ts:9:5 - (ae-forgotten-export) The symbol "ApiProviderProps" needs to be exported by the entry point index.d.ts +// src/app/types.d.ts:88:5 - (ae-forgotten-export) The symbol "UnknownPluginOutput" needs to be exported by the entry point index.d.ts +// src/app/types.d.ts:99:5 - (ae-forgotten-export) The symbol "AppIcons" needs to be exported by the entry point index.d.ts + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 0f6773497b..204550323c 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "0.1.4", + "version": "0.1.7", "private": false, "publishConfig": { "access": "public", @@ -29,13 +29,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.1.4", - "@backstage/config": "^0.1.3", - "@backstage/core-plugin-api": "^0.1.3", - "@backstage/theme": "^0.2.8", - "@material-ui/core": "^4.11.0", + "@backstage/core-components": "^0.3.0", + "@backstage/config": "^0.1.6", + "@backstage/core-plugin-api": "^0.1.5", + "@backstage/theme": "^0.2.9", + "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@types/react": "^16.9", + "@types/react": "*", "@types/prop-types": "^15.7.3", "prop-types": "^15.7.2", "react": "^16.12.0", @@ -44,8 +44,8 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.7.3", - "@backstage/test-utils": "^0.1.14", + "@backstage/cli": "^0.7.7", + "@backstage/test-utils": "^0.1.16", "@backstage/test-utils-core": "^0.1.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/packages/core-app-api/src/routing/FlatRoutes.test.tsx b/packages/core-app-api/src/routing/FlatRoutes.test.tsx index a73534a272..d5201a6f57 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.test.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.test.tsx @@ -100,7 +100,6 @@ describe('FlatRoutes', () => { return <>Outlet: {useOutlet()}; }; - // The '/*' suffixes here are intentional and will be ignored by FlatRoutes const routes = ( <> }> @@ -112,11 +111,15 @@ describe('FlatRoutes', () => { }> b + }> + c + ); const renderRoute = makeRouteRenderer({routes}); expect(renderRoute('/a').getByText('Outlet: a')).toBeInTheDocument(); expect(renderRoute('/a/b').getByText('Outlet: a-b')).toBeInTheDocument(); expect(renderRoute('/b').getByText('Outlet: b')).toBeInTheDocument(); + expect(renderRoute('/').getByText('Outlet: c')).toBeInTheDocument(); }); }); diff --git a/packages/core-app-api/src/routing/FlatRoutes.tsx b/packages/core-app-api/src/routing/FlatRoutes.tsx index 6ba82203fd..315ec91cdb 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.tsx @@ -49,8 +49,10 @@ export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => { element: child, children: child.props.children ? [ + // These are the children of each route, which we all add in under a catch-all + // subroute in order to make them available to `useOutlet` { - path: '/*', + path: path === '/' ? '/' : '/*', // The root path must require an exact match element: child.props.children, }, ] diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 1536cf3fb2..cb93e38ba5 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,78 @@ # @backstage/core-components +## 0.3.0 + +### Minor Changes + +- 7bf006210: Remove unused props from InfoCard prop type + +### Patch Changes + +- c4d8ff963: Switched frontend identity code to use `token` instead of the deprecated `idToken` field +- 7b8aa8d0d: Move the `CreateComponentButton` from the catalog plugin to the `core-components` & rename it to `CreateButton` to be reused inside the api-docs plugin & scaffolder plugin, but also future plugins. Additionally, improve responsiveness of `CreateButton` & `SupportButton` by shrinking them to `IconButtons` on smaller screens. +- 260c053b9: Fix All Material UI Warnings +- Updated dependencies + - @backstage/config@0.1.6 + - @backstage/core-plugin-api@0.1.5 + +## 0.2.0 + +### Minor Changes + +- 9d40fcb1e: - Bumping `material-ui/core` version to at least `4.12.2` as they made some breaking changes in later versions which broke `Pagination` of the `Table`. + - Switching out `material-table` to `@material-table/core` for support for the later versions of `material-ui/core` + - This causes a minor API change to `@backstage/core-components` as the interface for `Table` re-exports the `prop` from the underlying `Table` components. + - `onChangeRowsPerPage` has been renamed to `onRowsPerPageChange` + - `onChangePage` has been renamed to `onPageChange` + - Migration guide is here: https://material-table-core.com/docs/breaking-changes + +### Patch Changes + +- 19d9995b6: Improve accessibility of core & catalog components by adjusting them with non-breaking changes. +- 224e54484: Added an `EntityProcessingErrorsPanel` component to show any errors that occurred when refreshing an entity from its source location. + + If upgrading, this should be added to your `EntityPage` in your Backstage application: + + ```diff + // packages/app/src/components/catalog/EntityPage.tsx + + const overviewContent = ( + ... + + + + + + + + + + + + + + + + + + + + ``` + + Additionally, `WarningPanel` now changes color based on the provided severity. + +- Updated dependencies + - @backstage/core-plugin-api@0.1.4 + - @backstage/theme@0.2.9 + +## 0.1.6 + +### Patch Changes + +- 9a751bb28: Increase the vertical padding of the sidebar search input field to match the height of the parent anchor tag. This prevents users from accidentally navigating to the search page when they actually wanted to use the search input directly. +- 45b5fc3a8: Updated the layout of catalog and API index pages to handle smaller screen sizes. This adds responsive wrappers to the entity tables, and switches filters to a drawer when width-constrained. If you have created a custom catalog or API index page, you will need to update the page structure to match the updated [catalog customization](https://backstage.io/docs/features/software-catalog/catalog-customization) documentation. +- 03bf17e9b: Improve the responsiveness of the EntityPage UI. With this the Header component should scale with the screen size & wrapping should not cause overflowing/blocking of links. Additionally enforce the Pages using the Grid Layout to use it across all screen sizes & to wrap as intended. + + To benefit from the improved responsive layout, the `EntityPage` in existing Backstage applications should be updated to set the `xs` column size on each grid item in the page, as this does not default. For example: + + ```diff + - + + + ``` + ## 0.1.5 ### Patch Changes diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 3d8e60d4fb..42404fb0c0 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -11,7 +11,7 @@ import { Breadcrumbs as Breadcrumbs_2 } from '@material-ui/core'; import { ButtonProps } from '@material-ui/core'; import { ButtonTypeMap } from '@material-ui/core'; import { CardHeaderProps } from '@material-ui/core'; -import { Column } from 'material-table'; +import { Column } from '@material-table/core'; import { CommonProps } from '@material-ui/core/OverridableComponent'; import { ComponentClass } from 'react'; import { ComponentProps } from 'react'; @@ -26,7 +26,7 @@ import { IconComponent } from '@backstage/core-plugin-api'; import { LinearProgressProps } from '@material-ui/core'; import { LinkProps as LinkProps_2 } from '@material-ui/core'; import { LinkProps as LinkProps_3 } from 'react-router-dom'; -import { MaterialTableProps } from 'material-table'; +import { MaterialTableProps } from '@material-table/core'; import { NavLinkProps } from 'react-router-dom'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; @@ -47,9 +47,13 @@ import { Theme } from '@material-ui/core'; import { TooltipProps } from '@material-ui/core'; import { WithStyles } from '@material-ui/core'; +// Warning: (ae-missing-release-tag) "AlertDisplay" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const AlertDisplay: () => JSX.Element | null; +// Warning: (ae-missing-release-tag) "Alignment" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) enum Alignment { // (undocumented) @@ -62,6 +66,9 @@ enum Alignment { UP_RIGHT = 'UR', } +// Warning: (ae-forgotten-export) The symbol "AvatarProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Avatar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Avatar: ({ displayName, @@ -69,12 +76,20 @@ export const Avatar: ({ customStyles, }: AvatarProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Breadcrumbs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) -export const Breadcrumbs: ({ children, ...props }: Props_25) => JSX.Element; +export const Breadcrumbs: ({ children, ...props }: Props_24) => JSX.Element; +// Warning: (ae-missing-release-tag) "BrokenImageIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const BrokenImageIcon: IconComponent; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Button" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const Button: React_2.ForwardRefExoticComponent< Pick< @@ -384,18 +399,28 @@ export const Button: React_2.ForwardRefExoticComponent< React_2.RefAttributes >; +// Warning: (ae-forgotten-export) The symbol "CardTabProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "CardTab" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const CardTab: ({ children, ...props }: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "CatalogIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const CatalogIcon: IconComponent; +// Warning: (ae-missing-release-tag) "ChatIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ChatIcon: IconComponent; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "CodeSnippet" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const CodeSnippet: ({ text, @@ -406,6 +431,9 @@ export const CodeSnippet: ({ customStyle, }: Props_2) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Content" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Content: ({ className, @@ -413,8 +441,11 @@ export const Content: ({ noPadding, children, ...props -}: PropsWithChildren) => JSX.Element; +}: PropsWithChildren) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "ContentHeaderProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ContentHeader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ContentHeader: ({ description, @@ -424,6 +455,8 @@ export const ContentHeader: ({ textAlign, }: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "CopyTextButton" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const CopyTextButton: { (props: Props_3): JSX.Element; @@ -434,9 +467,23 @@ export const CopyTextButton: { }; }; +// Warning: (ae-forgotten-export) The symbol "CreateButtonProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "CreateButton" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const CreateButton: ({ + title, + to, +}: CreateButtonProps) => JSX.Element | null; + +// Warning: (ae-missing-release-tag) "DashboardIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const DashboardIcon: IconComponent; +// Warning: (ae-forgotten-export) The symbol "CustomType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "DependencyEdge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type DependencyEdge = T & { from: string; @@ -444,6 +491,9 @@ type DependencyEdge = T & { label?: string; }; +// Warning: (ae-forgotten-export) The symbol "DependencyGraphProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "DependencyGraph" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function DependencyGraph({ edges, @@ -486,11 +536,15 @@ declare namespace DependencyGraphTypes { } export { DependencyGraphTypes }; +// Warning: (ae-missing-release-tag) "DependencyNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type DependencyNode = T & { id: string; }; +// Warning: (ae-missing-release-tag) "Direction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) enum Direction { // (undocumented) @@ -503,6 +557,9 @@ enum Direction { TOP_BOTTOM = 'TB', } +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "DismissableBanner" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const DismissableBanner: ({ variant, @@ -511,9 +568,13 @@ export const DismissableBanner: ({ fixed, }: Props_4) => JSX.Element; +// Warning: (ae-missing-release-tag) "DocsIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const DocsIcon: IconComponent; +// Warning: (ae-missing-release-tag) "EdgeProperties" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type EdgeProperties = { label?: string; @@ -526,9 +587,14 @@ type EdgeProperties = { [customKey: string]: any; }; +// Warning: (ae-missing-release-tag) "EmailIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const EmailIcon: IconComponent; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "EmptyState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const EmptyState: ({ title, @@ -537,15 +603,23 @@ export const EmptyState: ({ action, }: Props_5) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "State" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ErrorBoundary" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ErrorBoundary: ComponentClass; +// Warning: (ae-missing-release-tag) "ErrorBoundaryProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ErrorBoundaryProps = { slackChannel?: string | SlackChannel; onError?: (error: Error, errorInfo: string) => null; }; +// Warning: (ae-forgotten-export) The symbol "IErrorPageProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ErrorPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const ErrorPage: ({ status, @@ -553,6 +627,8 @@ export const ErrorPage: ({ additionalInfo, }: IErrorPageProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "ErrorPanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ErrorPanel: ({ title, @@ -561,6 +637,8 @@ export const ErrorPanel: ({ children, }: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "ErrorPanelProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ErrorPanelProps = { error: Error; @@ -568,6 +646,9 @@ export type ErrorPanelProps = { title?: string; }; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "FeatureCalloutCircular" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const FeatureCalloutCircular: ({ featureId, @@ -576,26 +657,43 @@ export const FeatureCalloutCircular: ({ children, }: PropsWithChildren) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Gauge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Gauge: (props: Props_14) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "GaugeCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const GaugeCard: (props: Props_13) => JSX.Element; +// Warning: (ae-missing-release-tag) "GitHubIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const GitHubIcon: IconComponent; +// Warning: (ae-missing-release-tag) "GraphEdge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type GraphEdge = DependencyEdge & dagre_2.GraphEdge & EdgeProperties; +// Warning: (ae-missing-release-tag) "GraphNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type GraphNode = dagre_2.Node>; +// Warning: (ae-missing-release-tag) "GroupIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const GroupIcon: IconComponent; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Header" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Header: ({ children, @@ -606,11 +704,17 @@ export const Header: ({ tooltip, type, typeLink, -}: PropsWithChildren) => JSX.Element; +}: PropsWithChildren) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "HeaderIconLinkRow" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HeaderIconLinkRow: ({ links }: Props_8) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "HeaderLabelProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "HeaderLabel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HeaderLabel: ({ label, @@ -618,6 +722,9 @@ export const HeaderLabel: ({ url, }: HeaderLabelProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "HeaderTabsProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "HeaderTabs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HeaderTabs: ({ tabs, @@ -625,17 +732,26 @@ export const HeaderTabs: ({ selectedIndex, }: HeaderTabsProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "HelpIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HelpIcon: IconComponent; +// Warning: (ae-missing-release-tag) "HomepageTimer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HomepageTimer: () => JSX.Element | null; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "HorizontalScrollGrid" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const HorizontalScrollGrid: ( props: PropsWithChildren, ) => JSX.Element; +// Warning: (ae-missing-release-tag) "IconLinkVerticalProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type IconLinkVerticalProps = { color?: 'primary' | 'secondary'; @@ -647,6 +763,9 @@ export type IconLinkVerticalProps = { title?: string; }; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "InfoCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const InfoCard: ({ title, @@ -667,14 +786,24 @@ export const InfoCard: ({ className, noPadding, titleTypographyProps, -}: Props_20) => JSX.Element; +}: Props_19) => JSX.Element; +// Warning: (ae-missing-release-tag) "InfoCardVariants" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type InfoCardVariants = 'flex' | 'fullHeight' | 'gridItem'; +// Warning: (ae-forgotten-export) The symbol "IntroCardProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IntroCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const IntroCard: (props: IntroCardProps) => JSX.Element; +// Warning: (tsdoc-malformed-html-name) Invalid HTML element: Expecting an HTML name +// Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// Warning: (ae-forgotten-export) The symbol "ItemCardProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ItemCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public @deprecated export const ItemCard: ({ description, @@ -687,17 +816,39 @@ export const ItemCard: ({ href, }: ItemCardProps) => JSX.Element; +// Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-html-tag-missing-string) The HTML element has an invalid attribute: Expecting an HTML string starting with a single-quote or double-quote character +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (ae-missing-release-tag) "ItemCardGrid" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ItemCardGrid: (props: ItemCardGridProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "styles" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ItemCardGridProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ItemCardGridProps = Partial> & { children?: React_2.ReactNode; }; +// Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-html-tag-missing-string) The HTML element has an invalid attribute: Expecting an HTML string starting with a single-quote or double-quote character +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (ae-missing-release-tag) "ItemCardHeader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ItemCardHeader: (props: ItemCardHeaderProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "styles" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ItemCardHeaderProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type ItemCardHeaderProps = Partial> & { title?: React_2.ReactNode; @@ -705,6 +856,8 @@ export type ItemCardHeaderProps = Partial> & { children?: React_2.ReactNode; }; +// Warning: (ae-missing-release-tag) "LabelPosition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) enum LabelPosition { // (undocumented) @@ -715,12 +868,20 @@ enum LabelPosition { RIGHT = 'r', } +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Lifecycle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Lifecycle: (props: Props_10) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "LinearGauge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const LinearGauge: ({ value }: Props_15) => JSX.Element | null; +// Warning: (ae-missing-release-tag) "Link" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const Link: React_2.ForwardRefExoticComponent< Pick< @@ -1008,37 +1169,67 @@ export const Link: React_2.ForwardRefExoticComponent< React_2.RefAttributes >; +// Warning: (ae-missing-release-tag) "LinkProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type LinkProps = LinkProps_2 & LinkProps_3 & { component?: ElementType; }; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "MarkdownContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const MarkdownContent: ({ content, dialect }: Props_11) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "MissingAnnotationEmptyState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const MissingAnnotationEmptyState: ({ annotation, }: Props_6) => JSX.Element; +// Warning: (ae-missing-release-tag) "OAuthRequestDialog" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const OAuthRequestDialog: () => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "OverflowTooltip" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const OverflowTooltip: (props: Props_12) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Page" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Page: ({ themeId, children, -}: PropsWithChildren) => JSX.Element; +}: PropsWithChildren) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "PageWithHeaderProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "PageWithHeader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const PageWithHeader: ({ + themeId, + children, + ...props +}: PropsWithChildren) => JSX.Element; + +// Warning: (ae-missing-release-tag) "Progress" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Progress: ( props: PropsWithChildren, ) => JSX.Element; +// Warning: (ae-missing-release-tag) "Ranker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) enum Ranker { // (undocumented) @@ -1049,22 +1240,32 @@ enum Ranker { TIGHT_TREE = 'tight-tree', } +// Warning: (ae-missing-release-tag) "RenderLabelFunction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type RenderLabelFunction = (props: RenderLabelProps) => React.ReactNode; +// Warning: (ae-missing-release-tag) "RenderLabelProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type RenderLabelProps = { edge: DependencyEdge; }; +// Warning: (ae-missing-release-tag) "RenderNodeFunction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type RenderNodeFunction = (props: RenderNodeProps) => React.ReactNode; +// Warning: (ae-missing-release-tag) "RenderNodeProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) type RenderNodeProps = { node: DependencyNode; }; +// Warning: (ae-missing-release-tag) "ResponseErrorPanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const ResponseErrorPanel: ({ title, @@ -1072,9 +1273,14 @@ export const ResponseErrorPanel: ({ defaultExpanded, }: ErrorPanelProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "RoutedTabs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const RoutedTabs: ({ routes }: { routes: SubRoute_2[] }) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "SelectProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SelectComponent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Select: ({ multiple, @@ -1086,17 +1292,24 @@ export const Select: ({ triggerReset, }: SelectProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Sidebar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Sidebar: ({ openDelayMs, closeDelayMs, children, -}: PropsWithChildren) => JSX.Element; +}: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "SIDEBAR_INTRO_LOCAL_STORAGE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SIDEBAR_INTRO_LOCAL_STORAGE = '@backstage/core/sidebar-intro-dismissed'; +// Warning: (ae-missing-release-tag) "sidebarConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const sidebarConfig: { drawerWidthClosed: number; @@ -1113,14 +1326,20 @@ export const sidebarConfig: { userBadgeDiameter: number; }; +// Warning: (ae-missing-release-tag) "SidebarContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarContext: Context; +// Warning: (ae-missing-release-tag) "SidebarContextType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SidebarContextType = { isOpen: boolean; }; +// Warning: (ae-missing-release-tag) "SidebarDivider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarDivider: React_2.ComponentType< Pick< @@ -1388,26 +1607,39 @@ export const SidebarDivider: React_2.ComponentType< } >; +// Warning: (ae-missing-release-tag) "SidebarIntro" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarIntro: () => JSX.Element | null; +// Warning: (ae-forgotten-export) The symbol "SidebarItemProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SidebarItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarItem: React_2.ForwardRefExoticComponent< SidebarItemProps & React_2.RefAttributes >; +// Warning: (ae-missing-release-tag) "SidebarPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarPage: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "SidebarPinStateContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarPinStateContext: React_2.Context; +// Warning: (ae-missing-release-tag) "SidebarPinStateContextType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SidebarPinStateContextType = { isPinned: boolean; toggleSidebarPinState: () => any; }; +// Warning: (ae-missing-release-tag) "SidebarScrollWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarScrollWrapper: React_2.ComponentType< Pick< @@ -1675,11 +1907,16 @@ export const SidebarScrollWrapper: React_2.ComponentType< } >; +// Warning: (ae-forgotten-export) The symbol "SidebarSearchFieldProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SidebarSearchField" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarSearchField: ( props: SidebarSearchFieldProps, ) => JSX.Element; +// Warning: (ae-missing-release-tag) "SidebarSpace" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarSpace: React_2.ComponentType< Pick< @@ -1947,6 +2184,8 @@ export const SidebarSpace: React_2.ComponentType< } >; +// Warning: (ae-missing-release-tag) "SidebarSpacer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SidebarSpacer: React_2.ComponentType< Pick< @@ -2214,9 +2453,14 @@ export const SidebarSpacer: React_2.ComponentType< } >; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SignInPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) -export const SignInPage: (props: Props_23) => JSX.Element; +export const SignInPage: (props: Props_22) => JSX.Element; +// Warning: (ae-missing-release-tag) "SignInProviderConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SignInProviderConfig = { id: string; @@ -2225,6 +2469,9 @@ export type SignInProviderConfig = { apiRef: ApiRef; }; +// Warning: (ae-forgotten-export) The symbol "StepperProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SimpleStepper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SimpleStepper: ({ children, @@ -2233,6 +2480,9 @@ export const SimpleStepper: ({ activeStep, }: PropsWithChildren) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "StepProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SimpleStepperStep" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SimpleStepperStep: ({ title, @@ -2242,24 +2492,39 @@ export const SimpleStepperStep: ({ ...muiProps }: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusAborted" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusAborted: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusError: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusOK" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusOK: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusPending" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusPending: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusRunning" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusRunning: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-missing-release-tag) "StatusWarning" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StatusWarning: (props: PropsWithChildren<{}>) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "StructuredMetadataTable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const StructuredMetadataTable: ({ metadata, @@ -2267,24 +2532,34 @@ export const StructuredMetadataTable: ({ options, }: Props_16) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "SubvalueCellProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SubvalueCell" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SubvalueCell: ({ value, subvalue, }: SubvalueCellProps) => JSX.Element; +// Warning: (ae-forgotten-export) The symbol "SupportButtonProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SupportButton" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const SupportButton: ({ title, children, }: SupportButtonProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "SupportConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SupportConfig = { url: string; items: SupportItem[]; }; +// Warning: (ae-missing-release-tag) "SupportItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SupportItem = { title: string; @@ -2292,12 +2567,16 @@ export type SupportItem = { links: SupportItemLink[]; }; +// Warning: (ae-missing-release-tag) "SupportItemLink" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type SupportItemLink = { url: string; title: string; }; +// Warning: (ae-missing-release-tag) "Tab" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type Tab = { id: string; @@ -2310,6 +2589,9 @@ export type Tab = { >; }; +// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "TabbedCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const TabbedCard: ({ slackChannel, @@ -2319,14 +2601,18 @@ export const TabbedCard: ({ deepLink, value, onChange, -}: PropsWithChildren) => JSX.Element; +}: PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "TabbedLayout" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public export const TabbedLayout: { ({ children }: PropsWithChildren<{}>): JSX.Element; Route: (props: SubRoute) => null; }; +// Warning: (ae-missing-release-tag) "Table" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function Table({ columns, @@ -2340,6 +2626,8 @@ export function Table({ ...props }: TableProps): JSX.Element; +// Warning: (ae-missing-release-tag) "TableColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface TableColumn extends Column { // (undocumented) @@ -2348,12 +2636,16 @@ export interface TableColumn extends Column { width?: string; } +// Warning: (ae-missing-release-tag) "TableFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type TableFilter = { column: string; type: 'select' | 'multiple-select' | 'checkbox-tree'; }; +// Warning: (ae-missing-release-tag) "TableProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface TableProps extends MaterialTableProps { @@ -2371,6 +2663,8 @@ export interface TableProps subtitle?: string; } +// Warning: (ae-missing-release-tag) "TableState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export type TableState = { search?: string; @@ -2378,9 +2672,14 @@ export type TableState = { filters?: SelectedFilters; }; +// Warning: (ae-forgotten-export) The symbol "TabsProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Tabs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const Tabs: ({ tabs }: TabsProps) => JSX.Element; +// Warning: (ae-missing-release-tag) "TrendLine" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const TrendLine: ( props: SparklinesProps & @@ -2389,23 +2688,61 @@ export const TrendLine: ( }, ) => JSX.Element | null; +// Warning: (ae-forgotten-export) The symbol "SetQueryParams" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "useQueryParamState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function useQueryParamState( stateName: string, debounceTime?: number, ): [T | undefined, SetQueryParams]; +// Warning: (ae-missing-release-tag) "UserIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const UserIcon: IconComponent; +// Warning: (ae-missing-release-tag) "useSupportConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export function useSupportConfig(): SupportConfig; +// Warning: (ae-missing-release-tag) "WarningIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export const WarningIcon: IconComponent; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// Warning: (ae-forgotten-export) The symbol "WarningProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "WarningPanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public -export const WarningPanel: (props: Props_17) => JSX.Element; +export const WarningPanel: ({ + severity, + title, + message, + children, + defaultExpanded, +}: WarningProps) => JSX.Element; + +// Warnings were encountered during analysis: +// +// src/components/CopyTextButton/CopyTextButton.d.ts:24:5 - (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// src/components/TabbedLayout/RoutedTabs.d.ts:9:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts +// src/components/TabbedLayout/TabbedLayout.d.ts:29:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts +// src/components/Table/Table.d.ts:15:5 - (ae-forgotten-export) The symbol "SelectedFilters" needs to be exported by the entry point index.d.ts +// src/layout/ErrorBoundary/ErrorBoundary.d.ts:7:5 - (ae-forgotten-export) The symbol "SlackChannel" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) ``` diff --git a/packages/core-components/package.json b/packages/core-components/package.json index b9d514d074..998af15f19 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.1.5", + "version": "0.3.0", "private": false, "publishConfig": { "access": "public", @@ -29,17 +29,17 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.5", - "@backstage/core-plugin-api": "^0.1.2", + "@backstage/config": "^0.1.6", + "@backstage/core-plugin-api": "^0.1.5", "@backstage/errors": "^0.1.1", - "@backstage/theme": "^0.2.8", - "@material-ui/core": "^4.11.0", + "@backstage/theme": "^0.2.9", + "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@testing-library/react-hooks": "^3.4.2", "@types/dagre": "^0.7.44", "@types/prop-types": "^15.7.3", - "@types/react": "^16.9", + "@types/react": "*", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", "classnames": "^2.2.6", @@ -50,7 +50,7 @@ "dagre": "^0.8.5", "immer": "^9.0.1", "lodash": "^4.17.15", - "material-table": "^1.69.1", + "@material-table/core": "^3.1.0", "pluralize": "^8.0.0", "prop-types": "^15.7.2", "qs": "^6.9.4", @@ -70,15 +70,15 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/core-app-api": "^0.1.4", - "@backstage/cli": "^0.7.3", - "@backstage/test-utils": "^0.1.13", + "@backstage/core-app-api": "^0.1.7", + "@backstage/cli": "^0.7.7", + "@backstage/test-utils": "^0.1.16", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", "@types/classnames": "^2.2.9", "@types/d3-selection": "^2.0.0", - "@types/d3-shape": "^2.0.0", + "@types/d3-shape": "^3.0.1", "@types/d3-zoom": "^2.0.0", "@types/google-protobuf": "^3.7.2", "@types/jest": "^26.0.7", diff --git a/packages/core-components/src/components/CreateButton/CreateButton.tsx b/packages/core-components/src/components/CreateButton/CreateButton.tsx new file mode 100644 index 0000000000..021e1b002d --- /dev/null +++ b/packages/core-components/src/components/CreateButton/CreateButton.tsx @@ -0,0 +1,51 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackstageTheme } from '@backstage/theme'; +import { Button, IconButton, useMediaQuery } from '@material-ui/core'; +import React from 'react'; +import { Link as RouterLink, LinkProps } from 'react-router-dom'; +import AddCircleOutline from '@material-ui/icons/AddCircleOutline'; + +type CreateButtonProps = { + title: string; +} & Partial>; + +export const CreateButton = ({ title, to }: CreateButtonProps) => { + const isXSScreen = useMediaQuery(theme => + theme.breakpoints.down('xs'), + ); + + if (!to) { + return null; + } + + return isXSScreen ? ( + + + + ) : ( + + ); +}; diff --git a/plugins/catalog/src/components/CreateComponentButton/index.ts b/packages/core-components/src/components/CreateButton/index.ts similarity index 90% rename from plugins/catalog/src/components/CreateComponentButton/index.ts rename to packages/core-components/src/components/CreateButton/index.ts index e525bef782..f0e4cbe646 100644 --- a/plugins/catalog/src/components/CreateComponentButton/index.ts +++ b/packages/core-components/src/components/CreateButton/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { CreateComponentButton } from './CreateComponentButton'; + +export { CreateButton } from './CreateButton'; diff --git a/packages/core-components/src/components/EmptyState/EmptyState.tsx b/packages/core-components/src/components/EmptyState/EmptyState.tsx index 1d8d5a798f..d916ad9a61 100644 --- a/packages/core-components/src/components/EmptyState/EmptyState.tsx +++ b/packages/core-components/src/components/EmptyState/EmptyState.tsx @@ -44,20 +44,22 @@ export const EmptyState = ({ title, description, missing, action }: Props) => { - - - {title} - - - {description} - - - {action} + + + + {title} + + + {description} + + + {action} + diff --git a/packages/core-components/src/components/EmptyState/EmptyStateImage.tsx b/packages/core-components/src/components/EmptyState/EmptyStateImage.tsx index a76f0863f7..660e7fc947 100644 --- a/packages/core-components/src/components/EmptyState/EmptyStateImage.tsx +++ b/packages/core-components/src/components/EmptyState/EmptyStateImage.tsx @@ -29,7 +29,7 @@ const useStyles = makeStyles({ generalImg: { width: '95%', zIndex: 2, - position: 'absolute', + position: 'relative', left: '50%', top: '50%', transform: 'translate(-50%, 15%)', diff --git a/packages/core-components/src/components/ErrorPanel/ErrorPanel.tsx b/packages/core-components/src/components/ErrorPanel/ErrorPanel.tsx index 14b5d50325..f9996b9b1f 100644 --- a/packages/core-components/src/components/ErrorPanel/ErrorPanel.tsx +++ b/packages/core-components/src/components/ErrorPanel/ErrorPanel.tsx @@ -100,6 +100,7 @@ export const ErrorPanel = ({ }: PropsWithChildren) => { return ( diff --git a/packages/core-components/src/components/Status/Status.tsx b/packages/core-components/src/components/Status/Status.tsx index 3d79c38581..0b370a1397 100644 --- a/packages/core-components/src/components/Status/Status.tsx +++ b/packages/core-components/src/components/Status/Status.tsx @@ -69,6 +69,7 @@ export const StatusOK = (props: PropsWithChildren<{}>) => {