diff --git a/.changeset/curly-rings-report.md b/.changeset/curly-rings-report.md deleted file mode 100644 index 554cd0d1a8..0000000000 --- a/.changeset/curly-rings-report.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/create-app': patch -'@backstage/plugin-catalog': patch ---- - -Addressed some peer dependency warnings diff --git a/.changeset/five-lies-care.md b/.changeset/five-lies-care.md deleted file mode 100644 index dab3f55d52..0000000000 --- a/.changeset/five-lies-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Can specify allowedOwners to the RepoUrlPicker picker in a template definition diff --git a/.changeset/fluffy-countries-knock.md b/.changeset/fluffy-countries-knock.md deleted file mode 100644 index 44dddbbca7..0000000000 --- a/.changeset/fluffy-countries-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Bump esbuild to ^0.14.1 diff --git a/.changeset/fresh-radios-compete.md b/.changeset/fresh-radios-compete.md deleted file mode 100644 index 221072eb95..0000000000 --- a/.changeset/fresh-radios-compete.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-kubernetes': minor -'@backstage/plugin-kubernetes-backend': minor -'@backstage/plugin-kubernetes-common': minor ---- - -Add pod metrics lookup and display in pod table. - -## Backwards incompatible changes - -If your Kubernetes distribution does not have the [metrics server](https://github.com/kubernetes-sigs/metrics-server) installed, -you will need to set the `skipMetricsLookup` config flag to `false`. - -See the [configuration docs](https://backstage.io/docs/features/kubernetes/configuration) for more details. diff --git a/.changeset/hot-dragons-kneel.md b/.changeset/hot-dragons-kneel.md deleted file mode 100644 index a2b6241b69..0000000000 --- a/.changeset/hot-dragons-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Reject catalog entities that have duplicate fields that vary only in casing. diff --git a/.changeset/light-pigs-protect.md b/.changeset/light-pigs-protect.md deleted file mode 100644 index 358547af8a..0000000000 --- a/.changeset/light-pigs-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Fix bug with setting owner in RepoUrlPicker causing validation failure diff --git a/.changeset/olive-pens-poke.md b/.changeset/olive-pens-poke.md deleted file mode 100644 index 8a009af971..0000000000 --- a/.changeset/olive-pens-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Use ellipsis style for overflowed text in sidebar menu diff --git a/.changeset/pretty-eagles-relate.md b/.changeset/pretty-eagles-relate.md deleted file mode 100644 index 9e17be05d3..0000000000 --- a/.changeset/pretty-eagles-relate.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add cli option to minify the generated code of a plugin or backend package - -``` -backstage-cli plugin:build --minify -backstage-cli backend:build --minify -``` diff --git a/.changeset/rotten-candles-poke.md b/.changeset/rotten-candles-poke.md deleted file mode 100644 index b8a5b7138b..0000000000 --- a/.changeset/rotten-candles-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Update AsyncAPI component to 1.0.0-x releases diff --git a/.changeset/search-hip-schools-burn.md b/.changeset/search-hip-schools-burn.md deleted file mode 100644 index 12cef5f5ca..0000000000 --- a/.changeset/search-hip-schools-burn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Export SearchApi interface from plugin diff --git a/.changeset/sixty-files-talk.md b/.changeset/sixty-files-talk.md deleted file mode 100644 index 67d8c48b7e..0000000000 --- a/.changeset/sixty-files-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-analytics-module-ga': patch ---- - -Support self hosted analytics.js script via `scriptSrc` config option diff --git a/.changeset/swift-clocks-cry.md b/.changeset/swift-clocks-cry.md deleted file mode 100644 index 8f37a2e340..0000000000 --- a/.changeset/swift-clocks-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Add knexConfig config section diff --git a/.changeset/techdocs-satisfied-you-blinked.md b/.changeset/techdocs-satisfied-you-blinked.md deleted file mode 100644 index 4cbc9d4f3e..0000000000 --- a/.changeset/techdocs-satisfied-you-blinked.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/techdocs-common': minor -'@backstage/plugin-techdocs-backend': minor ---- - -Added the ability for the TechDocs Backend to (optionally) leverage a cache -store to improve performance when reading files from a cloud storage provider. diff --git a/.changeset/the-renegade-feeling.md b/.changeset/the-renegade-feeling.md deleted file mode 100644 index c9a4b1965e..0000000000 --- a/.changeset/the-renegade-feeling.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -TechDocs Backend may now (optionally) leverage a cache store to improve -performance when reading content from a cloud storage provider. - -To apply this change to an existing app, pass the cache manager from the plugin -environment to the `createRouter` function in your backend: - -```diff -// packages/backend/src/plugins/techdocs.ts - -export default async function createPlugin({ - logger, - config, - discovery, - reader, -+ cache, -}: PluginEnvironment): Promise { - - // ... - - return await createRouter({ - preparers, - generators, - publisher, - logger, - config, - discovery, -+ cache, - }); -``` - -If your `PluginEnvironment` does not include a cache manager, be sure you've -applied [the cache management change][cm-change] to your backend as well. - -[Additional configuration][td-rec-arch] is required if you wish to enable -caching in TechDocs. - -[cm-change]: https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md#patch-changes-6 -[td-rec-arch]: https://backstage.io/docs/features/techdocs/architecture#recommended-deployment diff --git a/.changeset/thirty-readers-attack.md b/.changeset/thirty-readers-attack.md deleted file mode 100644 index cd05f4ebf4..0000000000 --- a/.changeset/thirty-readers-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bump @spotify/prettier-config diff --git a/.changeset/three-coins-kiss.md b/.changeset/three-coins-kiss.md deleted file mode 100644 index a4b0c83288..0000000000 --- a/.changeset/three-coins-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-xcmetrics': patch ---- - -Handle a case where XCode data from backend (before 0.0.8) could be missing diff --git a/.changeset/three-news-worry.md b/.changeset/three-news-worry.md deleted file mode 100644 index 24c7daa240..0000000000 --- a/.changeset/three-news-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar-backend': patch ---- - -Handle migration error when old data is present in the database diff --git a/.changeset/tiny-trains-notice.md b/.changeset/tiny-trains-notice.md deleted file mode 100644 index e6d260633e..0000000000 --- a/.changeset/tiny-trains-notice.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed the `scaffolder.github.visibility` configuration that is no longer used from the default app template. diff --git a/ADOPTERS.md b/ADOPTERS.md index 3a04099812..43e7fba68b 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -5,7 +5,7 @@ | [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. | +| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | 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. | diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 2cdf6f1b35..ed7a103bc4 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -11,13 +11,13 @@ would be good to also have some files in there that can be templated in. A simple `template.yaml` definition might look something like this: ```yaml -apiVersion: backstage.io/v1beta2 +apiVersion: scaffolder.backstage.io/v1beta3 kind: Template # some metadata about the template itself metadata: - name: v1beta2-demo + name: v1beta3-demo title: Test Action template - description: scaffolder v1beta2 template demo + description: scaffolder v1beta3 template demo spec: owner: backstage/techdocs-core type: service @@ -55,7 +55,7 @@ spec: input: url: ./template values: - name: '{{ parameters.name }}' + name: ${{ parameters.name }} - id: fetch-docs name: Fetch Docs @@ -69,14 +69,14 @@ spec: action: publish:github input: allowedHosts: ['github.com'] - description: 'This is {{ parameters.name }}' - repoUrl: '{{ parameters.repoUrl }}' + description: This is ${{ parameters.name }} + repoUrl: ${{ parameters.repoUrl }} - id: register name: Register action: catalog:register input: - repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}' + repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }} catalogInfoPath: '/catalog-info.yaml' ``` diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 81f2622312..a1dffe1580 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -6,21 +6,21 @@ description: Details around creating your own custom Software Templates Templates are stored in the **Software Catalog** under a kind `Template`. You can create your own templates with a small `yaml` definition which describes the -template and it's metadata, along with some input variables that your template +template and its metadata, along with some input variables that your template will need, and then a list of actions which are then executed by the scaffolding service. Let's take a look at a simple example: ```yaml -# Notice the v1beta2 version -apiVersion: backstage.io/v1beta2 +# Notice the v1beta3 version +apiVersion: scaffolder.backstage.io/v1beta3 kind: Template # some metadata about the template itself metadata: - name: v1beta2-demo + name: v1beta3-demo title: Test Action template - description: scaffolder v1beta2 template demo + description: scaffolder v1beta3 template demo spec: owner: backstage/techdocs-core type: service @@ -66,8 +66,8 @@ spec: input: url: ./template values: - name: '{{ parameters.name }}' - owner: '{{ parameters.owner }}' + name: ${{ parameters.name }} + owner: ${{ parameters.owner }} - id: fetch-docs name: Fetch Docs @@ -81,20 +81,20 @@ spec: action: publish:github input: allowedHosts: ['github.com'] - description: 'This is {{ parameters.name }}' - repoUrl: '{{ parameters.repoUrl }}' + description: This is ${{ parameters.name }} + repoUrl: ${{ parameters.repoUrl }} - id: register name: Register action: catalog:register input: - repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}' + repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }} catalogInfoPath: '/catalog-info.yaml' # some outputs which are saved along with the job for use in the frontend output: - remoteUrl: '{{ steps.publish.output.remoteUrl }}' - entityRef: '{{ steps.register.output.entityRef }}' + remoteUrl: ${{ steps.publish.output.remoteUrl }} + entityRef: ${{ steps.register.output.entityRef }} ``` Let's dive in and pick apart what each of these sections do and what they are. @@ -183,12 +183,12 @@ this: It would look something like the following in a template: ```yaml -apiVersion: backstage.io/v1beta2 +apiVersion: scaffolder.backstage.io/v1beta3 kind: Template metadata: - name: v1beta2-demo + name: v1beta3-demo title: Test Action template - description: scaffolder v1beta2 template demo + description: scaffolder v1beta3 template demo spec: owner: backstage/techdocs-core type: service @@ -315,12 +315,12 @@ template. These follow the same standard format: ```yaml - id: fetch-base # A unique id for the step name: Fetch Base # A title displayed in the frontend - if: '{{ parameters.name }}' # Optional condition, skip the step if not truthy + if: ${{ parameters.name }} # Optional condition, skip the step if not truthy action: fetch:template # An action to call input: # Input that is passed as arguments to the action handler url: ./template values: - name: '{{ parameters.name }}' + name: ${{ parameters.name }} ``` By default we ship some [built in actions](./builtin-actions.md) that you can @@ -338,22 +338,19 @@ The main two that are used are the following: ```yaml output: - remoteUrl: '{{ steps.publish.output.remoteUrl }}' # link to the remote repository - entityRef: '{{ steps.register.output.entityRef }}' # link to the entity that has been ingested to the catalog + remoteUrl: ${{ steps.publish.output.remoteUrl }} # link to the remote repository + entityRef: ${{ steps.register.output.entityRef }} # link to the entity that has been ingested to the catalog ``` ### The templating syntax -You might have noticed variables wrapped in `{{ }}` in the examples. These are -`handlebars` template strings for linking and gluing the different parts of the -template together. All the form inputs from the `parameters` section will be -available by using this template syntax (for example, -`{{ parameters.firstName }}` inserts the value of `firstName` from the -parameters). This is great for passing the values from the form into different -steps and reusing these input variables. To pass arrays or objects use the -`json` custom [helper](https://handlebarsjs.com/guide/expressions.html#helpers). -For example, `{{ json parameters.nicknames }}` will insert the result of calling -`JSON.stringify` on the value of the `nicknames` parameter. +You might have noticed variables wrapped in `${{ }}` in the examples. These are +template strings for linking and gluing the different parts of the template +together. All the form inputs from the `parameters` section will be available by +using this template syntax (for example, `${{ parameters.firstName }}` inserts +the value of `firstName` from the parameters). This is great for passing the +values from the form into different steps and reusing these input variables. +These template strings preserve the type of the parameter. As you can see above in the `Outputs` section, `actions` and `steps` can also output things. You can grab that output using `steps.$stepId.output.$property`. diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index b2b50ae48b..b9a84d500c 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/app-defaults +## 0.1.2 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/core-app-api@0.2.0 + ## 0.1.1 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 695d457455..fc1bca2104 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "0.1.1", + "version": "0.1.2", "private": false, "publishConfig": { "access": "public", @@ -29,23 +29,25 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "react": "^16.12.0", "react-router-dom": "6.0.0-beta.0" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.22", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/react": "*" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist" diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 2d006791e9..3f3ac75853 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,50 @@ # example-app +## 0.2.56 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-cloudbuild@0.2.29 + - @backstage/plugin-catalog@0.7.4 + - @backstage/core-app-api@0.2.0 + - @backstage/plugin-scaffolder@0.11.14 + - @backstage/plugin-kubernetes@0.5.0 + - @backstage/app-defaults@0.1.2 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-api-docs@0.6.18 + - @backstage/plugin-azure-devops@0.1.6 + - @backstage/plugin-badges@0.2.16 + - @backstage/plugin-catalog-graph@0.2.3 + - @backstage/plugin-catalog-import@0.7.5 + - @backstage/plugin-catalog-react@0.6.5 + - @backstage/plugin-circleci@0.2.31 + - @backstage/plugin-code-coverage@0.1.19 + - @backstage/plugin-cost-insights@0.11.13 + - @backstage/plugin-explore@0.3.22 + - @backstage/plugin-gcp-projects@0.3.10 + - @backstage/plugin-github-actions@0.4.26 + - @backstage/plugin-graphiql@0.2.24 + - @backstage/plugin-home@0.4.7 + - @backstage/plugin-jenkins@0.5.14 + - @backstage/plugin-kafka@0.2.22 + - @backstage/plugin-lighthouse@0.2.31 + - @backstage/plugin-newrelic@0.3.10 + - @backstage/plugin-org@0.3.30 + - @backstage/plugin-pagerduty@0.3.19 + - @backstage/plugin-rollbar@0.3.20 + - @backstage/plugin-search@0.5.1 + - @backstage/plugin-sentry@0.3.30 + - @backstage/plugin-shortcuts@0.1.15 + - @backstage/plugin-tech-insights@0.1.1 + - @backstage/plugin-tech-radar@0.4.13 + - @backstage/plugin-techdocs@0.12.9 + - @backstage/plugin-todo@0.1.16 + - @backstage/plugin-user-settings@0.3.13 + - @backstage/cli@0.10.1 + ## 0.2.55 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 36b811c27d..daa7ad16f4 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,63 +1,62 @@ { "name": "example-app", - "version": "0.2.55", + "version": "0.2.56", "private": true, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^0.1.1", + "@backstage/app-defaults": "^0.1.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-api-docs": "^0.6.16", - "@backstage/plugin-azure-devops": "^0.1.5", - "@backstage/plugin-badges": "^0.2.14", - "@backstage/plugin-catalog": "^0.7.3", - "@backstage/plugin-catalog-graph": "^0.2.2", - "@backstage/plugin-catalog-import": "^0.7.4", - "@backstage/plugin-catalog-react": "^0.6.4", - "@backstage/plugin-circleci": "^0.2.30", - "@backstage/plugin-cloudbuild": "^0.2.28", - "@backstage/plugin-code-coverage": "^0.1.18", - "@backstage/plugin-cost-insights": "^0.11.11", - "@backstage/plugin-explore": "^0.3.21", - "@backstage/plugin-gcp-projects": "^0.3.9", - "@backstage/plugin-github-actions": "^0.4.24", - "@backstage/plugin-graphiql": "^0.2.21", - "@backstage/plugin-home": "^0.4.6", - "@backstage/plugin-jenkins": "^0.5.12", - "@backstage/plugin-kafka": "^0.2.21", - "@backstage/plugin-kubernetes": "^0.4.22", - "@backstage/plugin-lighthouse": "^0.2.30", - "@backstage/plugin-newrelic": "^0.3.9", - "@backstage/plugin-org": "^0.3.28", - "@backstage/plugin-pagerduty": "0.3.18", - "@backstage/plugin-rollbar": "^0.3.19", - "@backstage/plugin-scaffolder": "^0.11.13", - "@backstage/plugin-search": "^0.5.0", - "@backstage/plugin-sentry": "^0.3.29", - "@backstage/plugin-shortcuts": "^0.1.14", - "@backstage/plugin-tech-radar": "^0.4.12", - "@backstage/plugin-techdocs": "^0.12.8", - "@backstage/plugin-todo": "^0.1.15", - "@backstage/plugin-user-settings": "^0.3.12", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-api-docs": "^0.6.18", + "@backstage/plugin-azure-devops": "^0.1.6", + "@backstage/plugin-badges": "^0.2.16", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/plugin-catalog-graph": "^0.2.3", + "@backstage/plugin-catalog-import": "^0.7.5", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-circleci": "^0.2.31", + "@backstage/plugin-cloudbuild": "^0.2.29", + "@backstage/plugin-code-coverage": "^0.1.19", + "@backstage/plugin-cost-insights": "^0.11.13", + "@backstage/plugin-explore": "^0.3.22", + "@backstage/plugin-gcp-projects": "^0.3.10", + "@backstage/plugin-github-actions": "^0.4.26", + "@backstage/plugin-graphiql": "^0.2.24", + "@backstage/plugin-home": "^0.4.7", + "@backstage/plugin-jenkins": "^0.5.14", + "@backstage/plugin-kafka": "^0.2.22", + "@backstage/plugin-kubernetes": "^0.5.0", + "@backstage/plugin-lighthouse": "^0.2.31", + "@backstage/plugin-newrelic": "^0.3.10", + "@backstage/plugin-org": "^0.3.30", + "@backstage/plugin-pagerduty": "0.3.19", + "@backstage/plugin-rollbar": "^0.3.20", + "@backstage/plugin-scaffolder": "^0.11.14", + "@backstage/plugin-search": "^0.5.1", + "@backstage/plugin-sentry": "^0.3.30", + "@backstage/plugin-shortcuts": "^0.1.15", + "@backstage/plugin-tech-radar": "^0.4.13", + "@backstage/plugin-techdocs": "^0.12.9", + "@backstage/plugin-todo": "^0.1.16", + "@backstage/plugin-user-settings": "^0.3.13", "@backstage/search-common": "^0.2.0", - "@backstage/plugin-tech-insights": "^0.1.0", + "@backstage/plugin-tech-insights": "^0.1.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "@roadiehq/backstage-plugin-buildkite": "^1.0.8", "@roadiehq/backstage-plugin-github-insights": "^1.1.23", "@roadiehq/backstage-plugin-github-pull-requests": "^1.0.13", "@roadiehq/backstage-plugin-travis-ci": "^1.0.11", "history": "^5.0.0", "prop-types": "^15.7.2", - "react": "^16.12.0", - "react-dom": "^16.12.0", + "react": "^16.13.1", + "react-dom": "^16.13.1", "react-hot-loader": "^4.12.21", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", @@ -65,7 +64,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/test-utils": "^0.1.22", + "@backstage/test-utils": "^0.1.24", "@rjsf/core": "^3.2.1", "@testing-library/cypress": "^8.0.2", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 3b9b381380..9810f49386 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -106,10 +106,7 @@ import { EntityTechdocsContent } from '@backstage/plugin-techdocs'; import { EntityTodoContent } from '@backstage/plugin-todo'; import { Button, Grid } from '@material-ui/core'; import BadgeIcon from '@material-ui/icons/CallToAction'; -import { - EntityBuildkiteContent, - isBuildkiteAvailable, -} from '@roadiehq/backstage-plugin-buildkite'; + import { EntityGithubInsightsContent, EntityGithubInsightsLanguagesCard, @@ -168,10 +165,6 @@ export const cicdContent = ( - - - - diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index b2bf629bed..ad3fb33365 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-common +## 0.9.13 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- 5a008576c4: Add possibility to use custom error handler +- 98a9c35f0c: Add options argument to support additional database migrations configuration +- 6298de32dd: Add knexConfig config section + ## 0.9.12 ### Patch Changes diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 9c66c0573e..d20f568e98 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -175,23 +175,22 @@ export function createStatusCheckRouter(options: { // @public (undocumented) export class DatabaseManager { forPlugin(pluginId: string): PluginDatabaseManager; - static fromConfig(config: Config): DatabaseManager; + static fromConfig( + config: Config, + options?: DatabaseManagerOptions, + ): DatabaseManager; } +// @public +export type DatabaseManagerOptions = { + migrations?: PluginDatabaseManager['migrations']; +}; + // @public (undocumented) export class DockerContainerRunner implements ContainerRunner { - constructor({ dockerClient }: { dockerClient: Docker }); + constructor(options: { dockerClient: Docker }); // (undocumented) - runContainer({ - imageName, - command, - args, - logStream, - mountDirs, - workingDir, - envVars, - pullImage, - }: RunContainerOptions): Promise; + runContainer(options: RunContainerOptions): Promise; } // @public @@ -227,34 +226,17 @@ export function getVoidLogger(): winston.Logger; // @public (undocumented) export class Git { // (undocumented) - add({ dir, filepath }: { dir: string; filepath: string }): Promise; + add(options: { dir: string; filepath: string }): Promise; // (undocumented) - addRemote({ - dir, - url, - remote, - }: { + addRemote(options: { dir: string; remote: string; url: string; }): Promise; // (undocumented) - clone({ - url, - dir, - ref, - }: { - url: string; - dir: string; - ref?: string; - }): Promise; + clone(options: { url: string; dir: string; ref?: string }): Promise; // (undocumented) - commit({ - dir, - message, - author, - committer, - }: { + commit(options: { dir: string; message: string; author: { @@ -267,41 +249,22 @@ export class Git { }; }): Promise; // (undocumented) - currentBranch({ - dir, - fullName, - }: { + currentBranch(options: { dir: string; fullName?: boolean; }): Promise; // (undocumented) - fetch({ dir, remote }: { dir: string; remote?: string }): Promise; + fetch(options: { dir: string; remote?: string }): Promise; // (undocumented) - static fromAuth: ({ - username, - password, - logger, - }: { - username?: string | undefined; - password?: string | undefined; - logger?: Logger_2 | undefined; + static fromAuth: (options: { + username?: string; + password?: string; + logger?: Logger_2; }) => Git; // (undocumented) - init({ - dir, - defaultBranch, - }: { - dir: string; - defaultBranch?: string; - }): Promise; + init(options: { dir: string; defaultBranch?: string }): Promise; // (undocumented) - merge({ - dir, - theirs, - ours, - author, - committer, - }: { + merge(options: { dir: string; theirs: string; ours?: string; @@ -315,17 +278,11 @@ export class Git { }; }): Promise; // (undocumented) - push({ dir, remote }: { dir: string; remote: string }): Promise; + push(options: { dir: string; remote: string }): Promise; // (undocumented) - readCommit({ - dir, - sha, - }: { - dir: string; - sha: string; - }): Promise; + readCommit(options: { dir: string; sha: string }): Promise; // (undocumented) - resolveRef({ dir, ref }: { dir: string; ref: string }): Promise; + resolveRef(options: { dir: string; ref: string }): Promise; } // @public @@ -395,6 +352,9 @@ export type PluginCacheManager = { // @public export interface PluginDatabaseManager { getClient(): Promise; + migrations?: { + skip?: boolean; + }; } // @public @@ -561,6 +521,8 @@ export type ServiceBuilder = { setRequestLoggingHandler( requestLoggingHandler: RequestLoggingHandlerFactory, ): ServiceBuilder; + setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder; + disableDefaultErrorHandler(): ServiceBuilder; start(): Promise; }; @@ -623,8 +585,8 @@ export type UrlReaderPredicateTuple = { // @public export class UrlReaders { - static create({ logger, config, factories }: UrlReadersOptions): UrlReader; - static default({ logger, config, factories }: UrlReadersOptions): UrlReader; + static create(options: UrlReadersOptions): UrlReader; + static default(options: UrlReadersOptions): UrlReader; } // @public (undocumented) @@ -642,4 +604,8 @@ export function useHotCleanup( // @public export function useHotMemoize(_module: NodeModule, valueFactory: () => T): T; + +// Warnings were encountered during analysis: +// +// src/database/types.d.ts:23:12 - (tsdoc-undefined-tag) The TSDoc tag "@default" is not defined in this configuration ``` diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index e46d659175..130a3fcaa5 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.9.12", + "version": "0.9.13", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -81,8 +81,8 @@ } }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", "@types/concat-stream": "^1.6.0", diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index 1d2ff58b41..bd2e7b9f71 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -36,25 +36,45 @@ describe('DatabaseManager', () => { afterEach(() => jest.resetAllMocks()); describe('DatabaseManager.fromConfig', () => { - it('accesses the backend.database key', () => { - const config = new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, + const backendConfig = { + backend: { + database: { + client: 'pg', + connection: { + host: 'localhost', + user: 'foo', + password: 'bar', + database: 'foodb', }, }, - }); + }, + }; + + it('accesses the backend.database key', () => { + const config = new ConfigReader(backendConfig); const getConfigSpy = jest.spyOn(config, 'getConfig'); DatabaseManager.fromConfig(config); expect(getConfigSpy).toHaveBeenCalledWith('backend.database'); }); + + it('handles default options', () => { + const config = new ConfigReader(backendConfig); + const database = DatabaseManager.fromConfig(config); + const client = database.forPlugin('test'); + + expect(client.migrations?.skip).toBe(false); + }); + + it('handles migrations options', () => { + const config = new ConfigReader(backendConfig); + const database = DatabaseManager.fromConfig(config, { + migrations: { skip: true }, + }); + const client = database.forPlugin('test'); + + expect(client.migrations?.skip).toBe(true); + }); }); describe('DatabaseManager.forPlugin', () => { diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index a3f31e98f2..8e23a219ec 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -36,6 +36,15 @@ function pluginPath(pluginId: string): string { return `plugin.${pluginId}`; } +/** + * Configuration options object. + * + * @public + */ +export type DatabaseManagerOptions = { + migrations?: PluginDatabaseManager['migrations']; +}; + /** @public */ export class DatabaseManager { /** @@ -47,19 +56,25 @@ export class DatabaseManager { * names if config is not provided. * * @param config - The loaded application configuration. + * @param options - An optional configuration object. */ - static fromConfig(config: Config): DatabaseManager { + static fromConfig( + config: Config, + options?: DatabaseManagerOptions, + ): DatabaseManager { const databaseConfig = config.getConfig('backend.database'); return new DatabaseManager( databaseConfig, databaseConfig.getOptionalString('prefix'), + options, ); } private constructor( private readonly config: Config, private readonly prefix: string = 'backstage_plugin_', + private readonly options?: DatabaseManagerOptions, ) {} /** @@ -76,6 +91,10 @@ export class DatabaseManager { getClient(): Promise { return _this.getDatabase(pluginId); }, + migrations: { + skip: false, + ..._this.options?.migrations, + }, }; } diff --git a/packages/backend-common/src/database/types.ts b/packages/backend-common/src/database/types.ts index e96f86980b..344f1088b8 100644 --- a/packages/backend-common/src/database/types.ts +++ b/packages/backend-common/src/database/types.ts @@ -30,6 +30,18 @@ export interface PluginDatabaseManager { * stores so that plugins are discouraged from database integration. */ getClient(): Promise; + + /** + * This property is used to control the behavior of database migrations. + */ + migrations?: { + /** + * skip database migrations. Useful if connecting to a read-only database. + * + * @default false + */ + skip?: boolean; + }; } /** diff --git a/packages/backend-common/src/reading/UrlReaders.ts b/packages/backend-common/src/reading/UrlReaders.ts index 7120a9570f..a920ec080b 100644 --- a/packages/backend-common/src/reading/UrlReaders.ts +++ b/packages/backend-common/src/reading/UrlReaders.ts @@ -46,7 +46,8 @@ export class UrlReaders { /** * Creates a UrlReader without any known types. */ - static create({ logger, config, factories }: UrlReadersOptions): UrlReader { + static create(options: UrlReadersOptions): UrlReader { + const { logger, config, factories } = options; const mux = new UrlReaderPredicateMux(logger); const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config, @@ -68,7 +69,8 @@ export class UrlReaders { * * Any additional factories passed will be loaded before the default ones. */ - static default({ logger, config, factories = [] }: UrlReadersOptions) { + static default(options: UrlReadersOptions) { + const { logger, config, factories = [] } = options; return UrlReaders.create({ logger, config, diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts index 00b103b240..372ecb0260 100644 --- a/packages/backend-common/src/scm/git.ts +++ b/packages/backend-common/src/scm/git.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import git, { ProgressCallback, MergeResult, @@ -42,44 +43,32 @@ export class Git { }, ) {} - async add({ - dir, - filepath, - }: { - dir: string; - filepath: string; - }): Promise { + async add(options: { dir: string; filepath: string }): Promise { + const { dir, filepath } = options; this.config.logger?.info(`Adding file {dir=${dir},filepath=${filepath}}`); return git.add({ fs, dir, filepath }); } - async addRemote({ - dir, - url, - remote, - }: { + async addRemote(options: { dir: string; remote: string; url: string; }): Promise { + const { dir, url, remote } = options; this.config.logger?.info( `Creating new remote {dir=${dir},remote=${remote},url=${url}}`, ); return git.addRemote({ fs, dir, remote, url }); } - async commit({ - dir, - message, - author, - committer, - }: { + async commit(options: { dir: string; message: string; author: { name: string; email: string }; committer: { name: string; email: string }; }): Promise { + const { dir, message, author, committer } = options; this.config.logger?.info( `Committing file to repo {dir=${dir},message=${message}}`, ); @@ -87,15 +76,12 @@ export class Git { return git.commit({ fs, dir, message, author, committer }); } - async clone({ - url, - dir, - ref, - }: { + async clone(options: { url: string; dir: string; ref?: string; }): Promise { + const { url, dir, ref } = options; this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`); return git.clone({ fs, @@ -114,51 +100,35 @@ export class Git { } // https://isomorphic-git.org/docs/en/currentBranch - async currentBranch({ - dir, - fullName, - }: { + async currentBranch(options: { dir: string; fullName?: boolean; }): Promise { - const fullname = fullName ?? false; - return git.currentBranch({ fs, dir, fullname }) as Promise< + const { dir, fullName = false } = options; + return git.currentBranch({ fs, dir, fullname: fullName }) as Promise< string | undefined >; } // https://isomorphic-git.org/docs/en/fetch - async fetch({ - dir, - remote, - }: { - dir: string; - remote?: string; - }): Promise { - const remoteValue = remote ?? 'origin'; + async fetch(options: { dir: string; remote?: string }): Promise { + const { dir, remote = 'origin' } = options; this.config.logger?.info( - `Fetching remote=${remoteValue} for repository {dir=${dir}}`, + `Fetching remote=${remote} for repository {dir=${dir}}`, ); await git.fetch({ fs, http, dir, - remote: remoteValue, + remote, onProgress: this.onProgressHandler(), - headers: { - 'user-agent': 'git/@isomorphic-git', - }, + headers: { 'user-agent': 'git/@isomorphic-git' }, onAuth: this.onAuth, }); } - async init({ - dir, - defaultBranch = 'master', - }: { - dir: string; - defaultBranch?: string; - }): Promise { + async init(options: { dir: string; defaultBranch?: string }): Promise { + const { dir, defaultBranch = 'master' } = options; this.config.logger?.info(`Init git repository {dir=${dir}}`); return git.init({ @@ -169,19 +139,14 @@ export class Git { } // https://isomorphic-git.org/docs/en/merge - async merge({ - dir, - theirs, - ours, - author, - committer, - }: { + async merge(options: { dir: string; theirs: string; ours?: string; author: { name: string; email: string }; committer: { name: string; email: string }; }): Promise { + const { dir, theirs, ours, author, committer } = options; this.config.logger?.info( `Merging branch '${theirs}' into '${ours}' for repository {dir=${dir}}`, ); @@ -197,7 +162,8 @@ export class Git { }); } - async push({ dir, remote }: { dir: string; remote: string }) { + async push(options: { dir: string; remote: string }) { + const { dir, remote } = options; this.config.logger?.info( `Pushing directory to remote {dir=${dir},remote=${remote}}`, ); @@ -215,24 +181,17 @@ export class Git { } // https://isomorphic-git.org/docs/en/readCommit - async readCommit({ - dir, - sha, - }: { + async readCommit(options: { dir: string; sha: string; }): Promise { + const { dir, sha } = options; return git.readCommit({ fs, dir, oid: sha }); } // https://isomorphic-git.org/docs/en/resolveRef - async resolveRef({ - dir, - ref, - }: { - dir: string; - ref: string; - }): Promise { + async resolveRef(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; return git.resolveRef({ fs, dir, ref }); } @@ -256,13 +215,12 @@ export class Git { }; }; - static fromAuth = ({ - username, - password, - logger, - }: { + static fromAuth = (options: { username?: string; password?: string; logger?: Logger; - }) => new Git({ username, password, logger }); + }) => { + const { username, password, logger } = options; + return new Git({ username, password, logger }); + }; } diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts index bd97f444de..6229cbb683 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { applyCspDirectives } from './ServiceBuilderImpl'; +import { NextFunction, Request, Response } from 'express'; +import { applyCspDirectives, ServiceBuilderImpl } from './ServiceBuilderImpl'; describe('ServiceBuilderImpl', () => { describe('applyCspDirectives', () => { @@ -33,4 +34,27 @@ describe('ServiceBuilderImpl', () => { expect(result!['upgrade-insecure-requests']).toBeUndefined(); }); }); + + describe('setCustomErrorHandler', () => { + it('check if custom error handler is undefined', () => { + const serviceBuilder = new ServiceBuilderImpl(module); + const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder); + expect(serviceBuilderProto.errorHandler).toBeUndefined(); + }); + + it('adds custom error handler', () => { + const serviceBuilder = new ServiceBuilderImpl(module); + const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder); + const customErrorHandler = ( + error: Error, + _req: Request, + _res: Response, + next: NextFunction, + ) => { + next(error); + }; + serviceBuilderProto.setErrorHandler(customErrorHandler); + expect(serviceBuilderProto.errorHandler).toEqual(customErrorHandler); + }); + }); }); diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index b085cccfd6..54f145539f 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -17,7 +17,7 @@ import { Config } from '@backstage/config'; import compression from 'compression'; import cors from 'cors'; -import express, { Router } from 'express'; +import express, { Router, ErrorRequestHandler } from 'express'; import helmet from 'helmet'; import * as http from 'http'; import stoppable from 'stoppable'; @@ -25,7 +25,7 @@ import { Logger } from 'winston'; import { useHotCleanup } from '../../hot'; import { getRootLogger } from '../../logging'; import { - errorHandler, + errorHandler as defaultErrorHandler, notFoundHandler, requestLoggingHandler as defaultRequestLoggingHandler, } from '../../middleware'; @@ -66,6 +66,8 @@ export class ServiceBuilderImpl implements ServiceBuilder { private httpsSettings: HttpsSettings | undefined; private routers: [string, Router][]; private requestLoggingHandler: RequestLoggingHandlerFactory | undefined; + private errorHandler: ErrorRequestHandler | undefined; + private useDefaultErrorHandler: boolean; // Reference to the module where builder is created - needed for hot module // reloading private module: NodeModule; @@ -73,6 +75,7 @@ export class ServiceBuilderImpl implements ServiceBuilder { constructor(moduleRef: NodeModule) { this.routers = []; this.module = moduleRef; + this.useDefaultErrorHandler = true; } loadConfig(config: Config): ServiceBuilder { @@ -152,6 +155,16 @@ export class ServiceBuilderImpl implements ServiceBuilder { return this; } + setErrorHandler(errorHandler: ErrorRequestHandler) { + this.errorHandler = errorHandler; + return this; + } + + disableDefaultErrorHandler() { + this.useDefaultErrorHandler = false; + return this; + } + async start(): Promise { const app = express(); const { port, host, logger, corsOptions, httpsSettings, helmetOptions } = @@ -169,7 +182,14 @@ export class ServiceBuilderImpl implements ServiceBuilder { app.use(root, route); } app.use(notFoundHandler()); - app.use(errorHandler()); + + if (this.errorHandler) { + app.use(this.errorHandler); + } + + if (this.useDefaultErrorHandler) { + app.use(defaultErrorHandler()); + } const server: http.Server = httpsSettings ? await createHttpsServer(app, httpsSettings, logger) diff --git a/packages/backend-common/src/service/types.ts b/packages/backend-common/src/service/types.ts index 2ad379f31e..3e94196006 100644 --- a/packages/backend-common/src/service/types.ts +++ b/packages/backend-common/src/service/types.ts @@ -16,7 +16,7 @@ import { Config } from '@backstage/config'; import cors from 'cors'; -import { Router, RequestHandler } from 'express'; +import { Router, RequestHandler, ErrorRequestHandler } from 'express'; import { Server } from 'http'; import { Logger } from 'winston'; @@ -98,6 +98,21 @@ export type ServiceBuilder = { requestLoggingHandler: RequestLoggingHandlerFactory, ): ServiceBuilder; + /** + * Sets an additional errorHandler to run before the defaultErrorHandler. + * + * For execution of only the custom error handler make sure to also invoke disableDefaultErrorHandler() + * otherwise the defaultErrorHandler is executed at the end of the error middleware chain. + * + * @param errorHandler - an error handler + */ + setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder; + + /** + * Disables the default error handler + */ + disableDefaultErrorHandler(): ServiceBuilder; + /** * Starts the server using the given settings. */ diff --git a/packages/backend-common/src/util/DockerContainerRunner.ts b/packages/backend-common/src/util/DockerContainerRunner.ts index b81bd995ca..424913f316 100644 --- a/packages/backend-common/src/util/DockerContainerRunner.ts +++ b/packages/backend-common/src/util/DockerContainerRunner.ts @@ -28,20 +28,22 @@ export type UserOptions = { export class DockerContainerRunner implements ContainerRunner { private readonly dockerClient: Docker; - constructor({ dockerClient }: { dockerClient: Docker }) { - this.dockerClient = dockerClient; + constructor(options: { dockerClient: Docker }) { + this.dockerClient = options.dockerClient; } - async runContainer({ - imageName, - command, - args, - logStream = new PassThrough(), - mountDirs = {}, - workingDir, - envVars = {}, - pullImage = true, - }: RunContainerOptions) { + async runContainer(options: RunContainerOptions) { + const { + imageName, + command, + args, + logStream = new PassThrough(), + mountDirs = {}, + workingDir, + envVars = {}, + pullImage = true, + } = options; + // Show a better error message when Docker is unavailable. try { await this.dockerClient.ping(); diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 7aa2fb5f55..fa8632e2ef 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,24 @@ # example-backend +## 0.2.56 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.5.0 + - @backstage/plugin-scaffolder-backend@0.15.16 + - @backstage/plugin-kubernetes-backend@0.4.0 + - @backstage/backend-common@0.9.13 + - @backstage/plugin-catalog-backend@0.19.1 + - @backstage/plugin-search-backend@0.2.8 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.6 + - @backstage/plugin-search-backend-module-pg@0.2.2 + - @backstage/plugin-techdocs-backend@0.12.0 + - @backstage/plugin-todo-backend@0.1.15 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.0 + - @backstage/plugin-azure-devops-backend@0.2.4 + - example-app@0.2.56 + ## 0.2.55 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index cc8a8ac76a..ae61bc7a45 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.55", + "version": "0.2.56", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,39 +24,39 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", "@backstage/integration": "^0.6.10", "@backstage/plugin-app-backend": "^0.3.19", - "@backstage/plugin-auth-backend": "^0.4.10", - "@backstage/plugin-azure-devops-backend": "^0.2.3", + "@backstage/plugin-auth-backend": "^0.5.0", + "@backstage/plugin-azure-devops-backend": "^0.2.4", "@backstage/plugin-badges-backend": "^0.1.13", - "@backstage/plugin-catalog-backend": "^0.19.0", + "@backstage/plugin-catalog-backend": "^0.19.1", "@backstage/plugin-code-coverage-backend": "^0.1.16", "@backstage/plugin-graphql-backend": "^0.1.9", "@backstage/plugin-jenkins-backend": "^0.1.9", - "@backstage/plugin-kubernetes-backend": "^0.3.20", + "@backstage/plugin-kubernetes-backend": "^0.4.0", "@backstage/plugin-kafka-backend": "^0.2.12", "@backstage/plugin-proxy-backend": "^0.2.14", "@backstage/plugin-rollbar-backend": "^0.1.16", - "@backstage/plugin-scaffolder-backend": "^0.15.15", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.1.7", - "@backstage/plugin-search-backend": "^0.2.7", + "@backstage/plugin-scaffolder-backend": "^0.15.16", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.0", + "@backstage/plugin-search-backend": "^0.2.8", "@backstage/plugin-search-backend-node": "^0.4.2", - "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.5", - "@backstage/plugin-search-backend-module-pg": "^0.2.1", - "@backstage/plugin-techdocs-backend": "^0.11.0", + "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.6", + "@backstage/plugin-search-backend-module-pg": "^0.2.2", + "@backstage/plugin-techdocs-backend": "^0.12.0", "@backstage/plugin-tech-insights-backend": "^0.1.3", "@backstage/plugin-tech-insights-node": "^0.1.1", "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.2", - "@backstage/plugin-todo-backend": "^0.1.14", + "@backstage/plugin-todo-backend": "^0.1.15", "@gitbeaker/node": "^34.6.0", "@octokit/rest": "^18.5.3", "azure-devops-node-api": "^11.0.1", "dockerode": "^3.3.1", - "example-app": "^0.2.55", + "example-app": "^0.2.56", "express": "^4.17.1", "express-promise-router": "^4.1.0", "express-prom-bundle": "^6.3.6", @@ -68,7 +68,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6be3a461bf..0c30e8b251 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/cli +## 0.10.1 + +### Patch Changes + +- 0ebb05eee2: Add cli option to minify the generated code of a plugin or backend package + + ``` + backstage-cli plugin:build --minify + backstage-cli backend:build --minify + ``` + +- cd450844f6: Updated the frontend plugin template to put React dependencies in `peerDependencies` by default, as well as allowing both React v16 and v17. This change can be applied to existing plugins by running `yarn backstage-cli plugin:diff` within the plugin package directory. + ## 0.10.0 ### Minor Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index fe8a529de1..984c1c70d1 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.10.0", + "version": "0.10.1", "private": false, "publishConfig": { "access": "public" @@ -89,7 +89,6 @@ "ora": "^5.3.0", "postcss": "^8.1.0", "process": "^0.11.10", - "react": "^16.0.0", "react-dev-utils": "^12.0.0-next.47", "react-hot-loader": "^4.12.21", "recursive-readdir": "^2.2.2", @@ -117,13 +116,13 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@backstage/theme": "^0.2.14", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", diff --git a/packages/cli/src/lib/diff/handlers.ts b/packages/cli/src/lib/diff/handlers.ts index f8bbfa09ce..5bd90e3d22 100644 --- a/packages/cli/src/lib/diff/handlers.ts +++ b/packages/cli/src/lib/diff/handlers.ts @@ -75,7 +75,9 @@ class PackageJsonHandler { await this.syncScripts(); await this.syncPublishConfig(); await this.syncDependencies('dependencies'); + await this.syncDependencies('peerDependencies', true); await this.syncDependencies('devDependencies'); + await this.syncReactDeps(); } // Make sure a field inside package.json is in sync. This mutates the targetObj and writes package.json on change. @@ -207,12 +209,12 @@ class PackageJsonHandler { } } - private async syncDependencies(fieldName: string) { + private async syncDependencies(fieldName: string, required: boolean = false) { const pkgDeps = this.pkg[fieldName]; const targetDeps = (this.targetPkg[fieldName] = this.targetPkg[fieldName] || {}); - if (!pkgDeps) { + if (!pkgDeps && !required) { return; } @@ -231,10 +233,26 @@ class PackageJsonHandler { continue; } - await this.syncField(key, pkgDeps, targetDeps, fieldName, true, true); + await this.syncField( + key, + pkgDeps, + targetDeps, + fieldName, + true, + !required, + ); } } + private async syncReactDeps() { + const targetDeps = (this.targetPkg.dependencies = + this.targetPkg.dependencies || {}); + + // Remove these from from deps since they're now in peerDeps + await this.syncField('react', {}, targetDeps, 'dependencies'); + await this.syncField('react-dom', {}, targetDeps, 'dependencies'); + } + private async write() { await this.writeFunc(`${JSON.stringify(this.targetPkg, null, 2)}\n`); } diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index 3b512b22c3..d65e1e06d6 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -66,7 +66,7 @@ export const version = findVersion(); export const isDev = fs.pathExistsSync(paths.resolveOwn('src')); export function createPackageVersionProvider(lockfile?: Lockfile) { - return (name: string, versionHint?: string) => { + return (name: string, versionHint?: string): string => { const packageVersion = packageVersions[name]; const targetVersion = versionHint || packageVersion; if (!targetVersion) { @@ -94,6 +94,6 @@ export function createPackageVersionProvider(lockfile?: Lockfile) { if (semver.parse(versionHint)?.prerelease.length) { return versionHint!; } - return `^${versionHint}`; + return versionHint?.match(/^[\d\.]+$/) ? `^${versionHint}` : versionHint!; }; } diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index 624302da93..7461b0a57b 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -32,10 +32,11 @@ "@material-ui/core": "{{versionQuery '@material-ui/core' '4.12.2'}}", "@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}", "@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.57'}}", - "react": "{{versionQuery 'react' '16.13.1'}}", - "react-dom": "{{versionQuery 'react-dom' '16.13.1'}}", "react-use": "{{versionQuery 'react-use' '17.2.4'}}" }, + "peerDependencies": { + "react": "{{versionQuery 'react' '^16.13.1 || ^17.0.0'}}" + }, "devDependencies": { "@backstage/cli": "{{versionQuery '@backstage/cli'}}", "@backstage/core-app-api": "{{versionQuery '@backstage/core-app-api'}}", diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index dc2cc744f3..d7e402270a 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/codemods +## 0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/core-app-api@0.2.0 + ## 0.1.24 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 407c35c724..32bf6be518 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.24", + "version": "0.1.25", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index ff506f212f..ff15f45898 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/core-app-api +## 0.2.0 + +### Minor Changes + +- a036b65c2f: **BREAKING CHANGE** + + The app `SignInPage` component has been updated to switch out the `onResult` callback for a new `onSignInSuccess` callback. This is an immediate breaking change without any deprecation period, as it was deemed to be the way of making this change that had the lowest impact. + + The new `onSignInSuccess` callback directly accepts an implementation of an `IdentityApi`, rather than a `SignInResult`. The `SignInPage` from `@backstage/core-component` has been updated to fit this new API, and as long as you pass on `props` directly you should not see any breakage. + + However, if you implement your own custom `SignInPage`, then this will be a breaking change and you need to migrate over to using the new callback. While doing so you can take advantage of the `UserIdentity.fromLegacy` helper from `@backstage/core-components` to make the migration simpler by still using the `SignInResult` type. This helper is also deprecated though and is only provided for immediate migration. Long-term it will be necessary to build the `IdentityApi` using for example `UserIdentity.create` instead. + + The following is an example of how you can migrate existing usage immediately using `UserIdentity.fromLegacy`: + + ```ts + onResult(signInResult); + // becomes + onSignInSuccess(UserIdentity.fromLegacy(signInResult)); + ``` + + The following is an example of how implement the new `onSignInSuccess` callback of the `SignInPage` using `UserIdentity.create`: + + ```ts + const identityResponse = await authApi.getBackstageIdentity(); + // Profile is optional and will be removed, but allows the + // synchronous getProfile method of the IdentityApi to be used. + const profile = await authApi.getProfile(); + onSignInSuccess( + UserIdentity.create({ + identity: identityResponse.identity, + authApi, + profile, + }), + ); + ``` + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/app-defaults@0.1.2 + - @backstage/version-bridge@0.1.1 + ## 0.1.24 ### Patch Changes diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index e69ee4f325..51fd6bd06f 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -39,6 +39,7 @@ import { FeatureFlagsSaveOptions } from '@backstage/core-plugin-api'; import { gitlabAuthApiRef } from '@backstage/core-plugin-api'; import { googleAuthApiRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; +import { IdentityApi } from '@backstage/core-plugin-api'; import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; import { OAuthApi } from '@backstage/core-plugin-api'; import { OAuthRequestApi } from '@backstage/core-plugin-api'; @@ -250,24 +251,13 @@ export class AppThemeSelector implements AppThemeApi { // @public export class AtlassianAuth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - }: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T; } // @public export class Auth0Auth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - }: OAuthApiCreateOptions): typeof auth0AuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T; } // @public @@ -303,13 +293,7 @@ export type BackstagePluginWithAnyOutput = Omit< // @public export class BitbucketAuth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - }: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T; } // @public @@ -402,13 +386,7 @@ export class GithubAuth implements OAuthApi, SessionApi { // @deprecated constructor(sessionManager: SessionManager); // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - }: OAuthApiCreateOptions): GithubAuth; + static create(options: OAuthApiCreateOptions): GithubAuth; // (undocumented) getAccessToken(scope?: string, options?: AuthRequestOptions): Promise; // (undocumented) @@ -441,25 +419,13 @@ export type GithubSession = { // @public export class GitlabAuth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - }: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T; } // @public export class GoogleAuth { // (undocumented) - static create({ - discoveryApi, - oauthRequestApi, - environment, - provider, - defaultScopes, - }: OAuthApiCreateOptions): typeof googleAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T; } // @public @@ -477,13 +443,7 @@ export class LocalStorageFeatureFlags implements FeatureFlagsApi { // @public export class MicrosoftAuth { // (undocumented) - static create({ - environment, - provider, - oauthRequestApi, - discoveryApi, - defaultScopes, - }: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T; } // @public @@ -507,14 +467,7 @@ export class OAuth2 scopeTransform: (scopes: string[]) => string[]; }); // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - scopeTransform, - }: OAuth2CreateOptions): OAuth2; + static create(options: OAuth2CreateOptions): OAuth2; // (undocumented) getAccessToken( scope?: string | string[], @@ -570,24 +523,15 @@ export class OAuthRequestManager implements OAuthRequestApi { // @public export class OktaAuth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - defaultScopes, - }: OAuthApiCreateOptions): typeof oktaAuthApiRef.T; + static create(options: OAuthApiCreateOptions): typeof oktaAuthApiRef.T; } // @public export class OneLoginAuth { // (undocumented) - static create({ - discoveryApi, - environment, - provider, - oauthRequestApi, - }: OneLoginAuthCreateOptions): typeof oneloginAuthApiRef.T; + static create( + options: OneLoginAuthCreateOptions, + ): typeof oneloginAuthApiRef.T; } // @public @@ -607,11 +551,7 @@ export class SamlAuth // @deprecated constructor(sessionManager: SessionManager); // (undocumented) - static create({ - discoveryApi, - environment, - provider, - }: AuthApiCreateOptions): SamlAuth; + static create(options: AuthApiCreateOptions): SamlAuth; // (undocumented) getBackstageIdentity( options?: AuthRequestOptions, @@ -635,10 +575,10 @@ export type SamlSession = { // @public export type SignInPageProps = { - onResult(result: SignInResult): void; + onSignInSuccess(identityApi: IdentityApi): void; }; -// @public +// @public @deprecated export type SignInResult = { userId: string; profile: ProfileInfo; diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 9ab3e097d1..23079d7ba0 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.24", + "version": "0.2.0", "private": false, "publishConfig": { "access": "public", @@ -29,26 +29,28 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/app-defaults": "^0.1.1", - "@backstage/core-components": "^0.7.6", + "@backstage/app-defaults": "^0.1.2", + "@backstage/core-components": "^0.8.0", "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", - "@backstage/version-bridge": "^0.1.0", + "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@types/react": "*", "@types/prop-types": "^15.7.3", "prop-types": "^15.7.2", - "react": "^16.12.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts new file mode 100644 index 0000000000..8a2f12594c --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 { + IdentityApi, + ProfileInfo, + BackstageUserIdentity, +} from '@backstage/core-plugin-api'; + +function mkError(thing: string) { + return new Error( + `Tried to access IdentityApi ${thing} before app was loaded`, + ); +} + +/** + * Implementation of the connection between the App-wide IdentityApi + * and sign-in page. + */ +export class AppIdentityProxy implements IdentityApi { + private target?: IdentityApi; + + // This is called by the app manager once the sign-in page provides us with an implementation + setTarget(identityApi: IdentityApi) { + this.target = identityApi; + } + + getUserId(): string { + if (!this.target) { + throw mkError('getUserId'); + } + return this.target.getUserId(); + } + + getProfile(): ProfileInfo { + if (!this.target) { + throw mkError('getProfile'); + } + return this.target.getProfile(); + } + + async getProfileInfo(): Promise { + if (!this.target) { + throw mkError('getProfileInfo'); + } + return this.target.getProfileInfo(); + } + + async getBackstageIdentity(): Promise { + if (!this.target) { + throw mkError('getBackstageIdentity'); + } + return this.target.getBackstageIdentity(); + } + + async getCredentials(): Promise<{ token?: string | undefined }> { + if (!this.target) { + throw mkError('getCredentials'); + } + return this.target.getCredentials(); + } + + async getIdToken(): Promise { + if (!this.target) { + throw mkError('getIdToken'); + } + return this.target.getIdToken(); + } + + async signOut(): Promise { + if (!this.target) { + throw mkError('signOut'); + } + await this.target.signOut(); + location.reload(); + } +} diff --git a/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts b/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts index caad40ddbf..07ebefca28 100644 --- a/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts @@ -30,12 +30,14 @@ const DEFAULT_PROVIDER = { * @public */ export default class AtlassianAuth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - }: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts b/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts index 0a158ccb9e..d0a9dc5d99 100644 --- a/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts @@ -30,13 +30,15 @@ const DEFAULT_PROVIDER = { * @public */ export default class Auth0Auth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = ['openid', `email`, `profile`], - }: OAuthApiCreateOptions): typeof auth0AuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = ['openid', `email`, `profile`], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts index e488580c4d..c97cccc6ed 100644 --- a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts @@ -45,13 +45,15 @@ const DEFAULT_PROVIDER = { * @public */ export default class BitbucketAuth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = ['team'], - }: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = ['team'], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts index 3e9c899346..4da92efbdf 100644 --- a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts @@ -56,13 +56,15 @@ const DEFAULT_PROVIDER = { * @public */ export default class GithubAuth implements OAuthApi, SessionApi { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = ['read:user'], - }: OAuthApiCreateOptions) { + static create(options: OAuthApiCreateOptions) { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = ['read:user'], + } = options; + const connector = new DefaultAuthConnector({ discoveryApi, environment, diff --git a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts index f46f2ef72e..00085de8ac 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts @@ -30,13 +30,15 @@ const DEFAULT_PROVIDER = { * @public */ export default class GitlabAuth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = ['read_user'], - }: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = ['read_user'], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts index a6f37b250f..8a528f4511 100644 --- a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts @@ -32,17 +32,19 @@ const SCOPE_PREFIX = 'https://www.googleapis.com/auth/'; * @public */ export default class GoogleAuth { - static create({ - discoveryApi, - oauthRequestApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - defaultScopes = [ - 'openid', - `${SCOPE_PREFIX}userinfo.email`, - `${SCOPE_PREFIX}userinfo.profile`, - ], - }: OAuthApiCreateOptions): typeof googleAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T { + const { + discoveryApi, + oauthRequestApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + defaultScopes = [ + 'openid', + `${SCOPE_PREFIX}userinfo.email`, + `${SCOPE_PREFIX}userinfo.profile`, + ], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts index 148be66873..be5776609d 100644 --- a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts @@ -30,19 +30,21 @@ const DEFAULT_PROVIDER = { * @public */ export default class MicrosoftAuth { - static create({ - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - discoveryApi, - defaultScopes = [ - 'openid', - 'offline_access', - 'profile', - 'email', - 'User.Read', - ], - }: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T { + const { + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + discoveryApi, + defaultScopes = [ + 'openid', + 'offline_access', + 'profile', + 'email', + 'User.Read', + ], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts index 403e8445d8..582526083b 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -70,14 +70,16 @@ export default class OAuth2 BackstageIdentityApi, SessionApi { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = [], - scopeTransform = x => x, - }: OAuth2CreateOptions) { + static create(options: OAuth2CreateOptions) { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = [], + scopeTransform = x => x, + } = options; + const connector = new DefaultAuthConnector({ discoveryApi, environment, diff --git a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts index 465a124051..42c0ddd0ed 100644 --- a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -42,13 +42,15 @@ const OKTA_SCOPE_PREFIX: string = 'okta.'; * @public */ export default class OktaAuth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - defaultScopes = ['openid', 'email', 'profile', 'offline_access'], - }: OAuthApiCreateOptions): typeof oktaAuthApiRef.T { + static create(options: OAuthApiCreateOptions): typeof oktaAuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + defaultScopes = ['openid', 'email', 'profile', 'offline_access'], + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts index 93b9f6634c..9493d0809e 100644 --- a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts @@ -57,12 +57,16 @@ const SCOPE_PREFIX: string = 'onelogin.'; * @public */ export default class OneLoginAuth { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - oauthRequestApi, - }: OneLoginAuthCreateOptions): typeof oneloginAuthApiRef.T { + static create( + options: OneLoginAuthCreateOptions, + ): typeof oneloginAuthApiRef.T { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + } = options; + return OAuth2.create({ discoveryApi, oauthRequestApi, diff --git a/packages/core-app-api/src/apis/implementations/auth/saml/SamlAuth.ts b/packages/core-app-api/src/apis/implementations/auth/saml/SamlAuth.ts index c1b70e963d..5988e81c48 100644 --- a/packages/core-app-api/src/apis/implementations/auth/saml/SamlAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/saml/SamlAuth.ts @@ -52,11 +52,13 @@ const DEFAULT_PROVIDER = { export default class SamlAuth implements ProfileInfoApi, BackstageIdentityApi, SessionApi { - static create({ - discoveryApi, - environment = 'development', - provider = DEFAULT_PROVIDER, - }: AuthApiCreateOptions) { + static create(options: AuthApiCreateOptions) { + const { + discoveryApi, + environment = 'development', + provider = DEFAULT_PROVIDER, + } = options; + const connector = new DirectAuthConnector({ discoveryApi, environment, diff --git a/packages/core-app-api/src/app/AppIdentity.ts b/packages/core-app-api/src/app/AppIdentity.ts deleted file mode 100644 index 64e698102f..0000000000 --- a/packages/core-app-api/src/app/AppIdentity.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 { IdentityApi, ProfileInfo } from '@backstage/core-plugin-api'; -import { SignInResult } from './types'; - -/** - * Implementation of the connection between the App-wide IdentityApi - * and sign-in page. - */ -export class AppIdentity implements IdentityApi { - private hasIdentity = false; - private userId?: string; - private profile?: ProfileInfo; - private idTokenFunc?: () => Promise; - private signOutFunc?: () => Promise; - - getUserId(): string { - if (!this.hasIdentity) { - throw new Error( - 'Tried to access IdentityApi userId before app was loaded', - ); - } - return this.userId!; - } - - getProfile(): ProfileInfo { - if (!this.hasIdentity) { - throw new Error( - 'Tried to access IdentityApi profile before app was loaded', - ); - } - return this.profile!; - } - - async getIdToken(): Promise { - if (!this.hasIdentity) { - throw new Error( - 'Tried to access IdentityApi idToken before app was loaded', - ); - } - return this.idTokenFunc?.(); - } - - async signOut(): Promise { - if (!this.hasIdentity) { - throw new Error( - 'Tried to access IdentityApi signOutFunc before app was loaded', - ); - } - await this.signOutFunc?.(); - location.reload(); - } - - // This is indirectly called by the sign-in page to continue into the app. - setSignInResult(result: SignInResult) { - if (this.hasIdentity) { - return; - } - if (!result.userId) { - throw new Error('Invalid sign-in result, userId not set'); - } - if (!result.profile) { - throw new Error('Invalid sign-in result, profile not set'); - } - this.hasIdentity = true; - this.userId = result.userId; - this.profile = result.profile; - this.idTokenFunc = result.getIdToken; - this.signOutFunc = result.signOut; - } -} diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 5903a8c874..21940c08d5 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -43,12 +43,14 @@ import { AppThemeApi, ConfigApi, featureFlagsApiRef, + IdentityApi, identityApiRef, BackstagePlugin, RouteRef, SubRouteRef, ExternalRouteRef, } from '@backstage/core-plugin-api'; +import { UserIdentity } from '@backstage/core-components'; import { ApiFactoryRegistry, ApiResolver } from '../apis/system'; import { childDiscoverer, @@ -66,7 +68,7 @@ import { RoutingProvider } from '../routing/RoutingProvider'; import { RouteTracker } from '../routing/RouteTracker'; import { validateRoutes } from '../routing/validation'; import { AppContextProvider } from './AppContext'; -import { AppIdentity } from './AppIdentity'; +import { AppIdentityProxy } from '../apis/implementations/IdentityApi/AppIdentityProxy'; import { AppComponents, AppConfigLoader, @@ -75,7 +77,6 @@ import { AppRouteBinder, BackstageApp, SignInPageProps, - SignInResult, } from './types'; import { AppThemeProvider } from './AppThemeProvider'; import { defaultConfigLoader } from './defaultConfigLoader'; @@ -189,7 +190,7 @@ export class AppManager implements BackstageApp { private readonly defaultApis: Iterable; private readonly bindRoutes: AppOptions['bindRoutes']; - private readonly identityApi = new AppIdentity(); + private readonly appIdentityProxy = new AppIdentityProxy(); private readonly apiFactoryRegistry: ApiFactoryRegistry; constructor(options: AppOptions) { @@ -344,14 +345,14 @@ export class AppManager implements BackstageApp { component: ComponentType; children: ReactElement; }) => { - const [result, setResult] = useState(); + const [identityApi, setIdentityApi] = useState(); - if (result) { - this.identityApi.setSignInResult(result); - return children; + if (!identityApi) { + return ; } - return ; + this.appIdentityProxy.setTarget(identityApi); + return children; }; const AppRouter = ({ children }: PropsWithChildren<{}>) => { @@ -360,13 +361,7 @@ export class AppManager implements BackstageApp { // If the app hasn't configured a sign-in page, we just continue as guest. if (!SignInPageComponent) { - this.identityApi.setSignInResult({ - userId: 'guest', - profile: { - email: 'guest@example.com', - displayName: 'Guest', - }, - }); + this.appIdentityProxy.setTarget(UserIdentity.createGuest()); return ( @@ -430,7 +425,7 @@ export class AppManager implements BackstageApp { this.apiFactoryRegistry.register('static', { api: identityApiRef, deps: {}, - factory: () => this.identityApi, + factory: () => this.appIdentityProxy, }); // It's possible to replace the feature flag API, but since we must have at least diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index f16c8ac656..a538ccd366 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -25,6 +25,7 @@ import { SubRouteRef, ExternalRouteRef, PluginOutput, + IdentityApi, } from '@backstage/core-plugin-api'; import { AppConfig } from '@backstage/config'; @@ -42,6 +43,7 @@ export type BootErrorPageProps = { * The outcome of signing in on the sign-in page. * * @public + * @deprecated replaced by passing the {@link @backstage/core-plugin-api#IdentityApi} to the {@link SignInPageProps.onSignInSuccess} instead. */ export type SignInResult = { /** @@ -69,9 +71,9 @@ export type SignInResult = { */ export type SignInPageProps = { /** - * Set the sign-in result for the app. This should only be called once. + * Set the IdentityApi on successful sign in. This should only be called once. */ - onResult(result: SignInResult): void; + onSignInSuccess(identityApi: IdentityApi): void; }; /** diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 24d460279d..4eab9cea54 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/core-components +## 0.8.0 + +### Minor Changes + +- a036b65c2f: The `SignInPage` has been updated to use the new `onSignInSuccess` callback that was introduced in the same release. While existing code will usually continue to work, it is technically a breaking change because of the dependency on `SignInProps` from the `@backstage/core-plugin-api`. For more information on this change and instructions on how to migrate existing code, see the [`@backstage/core-app-api` CHANGELOG.md](https://github.com/backstage/backstage/blob/master/packages/core-app-api/CHANGELOG.md). + + Added a new `UserIdentity` class which helps create implementations of the `IdentityApi`. It provides a couple of static factory methods such as the most relevant `create`, and `createGuest` to create an `IdentityApi` for a guest user. + + Also provides a deprecated `fromLegacy` method to create an `IdentityApi` from the now deprecated `SignInResult`. This method will be removed in the future when `SignInResult` is also removed. + +### Patch Changes + +- 9603827bb5: Addressed some peer dependency warnings +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- e839500286: Introduce new `LogViewer` component that can be used to display logs. It supports copying, searching, filtering, and displaying text with ANSI color escape codes. +- 1357ac30f1: Standardize on `classnames` instead of both that and `clsx`. +- e5976071ea: Use ellipsis style for overflowed text in sidebar menu +- Updated dependencies + - @backstage/core-plugin-api@0.3.0 + ## 0.7.6 ### Patch Changes diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index a5f2010758..62b8b1f8c8 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -9,6 +9,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; import { BackstagePalette } from '@backstage/theme'; import { BackstageTheme } from '@backstage/theme'; +import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { BottomNavigationActionProps } from '@material-ui/core/BottomNavigationAction'; import { ButtonProps as ButtonProps_2 } from '@material-ui/core/Button'; import { CardHeaderProps } from '@material-ui/core/CardHeader'; @@ -21,6 +22,7 @@ import { CSSProperties } from 'react'; import { ElementType } from 'react'; import { ErrorInfo } from 'react'; import { IconComponent } from '@backstage/core-plugin-api'; +import { IdentityApi } from '@backstage/core-plugin-api'; import { LinearProgressProps } from '@material-ui/core/LinearProgress'; import { LinkProps as LinkProps_2 } from '@material-ui/core/Link'; import { LinkProps as LinkProps_3 } from 'react-router-dom'; @@ -28,6 +30,7 @@ import MaterialBreadcrumbs from '@material-ui/core/Breadcrumbs'; import { MaterialTableProps } from '@material-table/core'; import { NavLinkProps } from 'react-router-dom'; import { Overrides } from '@material-ui/core/styles/overrides'; +import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; @@ -36,6 +39,7 @@ import { ReactElement } from 'react'; import { ReactNode } from 'react'; import { SessionApi } from '@backstage/core-plugin-api'; import { SignInPageProps } from '@backstage/core-plugin-api'; +import { SignInResult } from '@backstage/core-plugin-api'; import { SparklinesLineProps } from 'react-sparklines'; import { SparklinesProps } from 'react-sparklines'; import { StyledComponentProps } from '@material-ui/core/styles'; @@ -606,6 +610,50 @@ export type LinkProps = LinkProps_2 & // @public (undocumented) export type LoginRequestListItemClassKey = 'root'; +// @public +export function LogViewer(props: LogViewerProps): JSX.Element; + +// @public +export type LogViewerClassKey = + | 'root' + | 'header' + | 'log' + | 'line' + | 'lineSelected' + | 'lineCopyButton' + | 'lineNumber' + | 'textHighlight' + | 'textSelectedHighlight' + | 'modifierBold' + | 'modifierItalic' + | 'modifierUnderline' + | 'modifierForegroundBlack' + | 'modifierForegroundRed' + | 'modifierForegroundGreen' + | 'modifierForegroundYellow' + | 'modifierForegroundBlue' + | 'modifierForegroundMagenta' + | 'modifierForegroundCyan' + | 'modifierForegroundWhite' + | 'modifierForegroundGrey' + | 'modifierBackgroundBlack' + | 'modifierBackgroundRed' + | 'modifierBackgroundGreen' + | 'modifierBackgroundYellow' + | 'modifierBackgroundBlue' + | 'modifierBackgroundMagenta' + | 'modifierBackgroundCyan' + | 'modifierBackgroundWhite' + | 'modifierBackgroundGrey'; + +// @public +export interface LogViewerProps { + classes?: { + root?: string; + }; + text: string; +} + // 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) // @@ -2014,10 +2062,7 @@ export const SidebarSpacer: React_2.ComponentType< >; // @public -export const SidebarSubmenu: ({ - title, - children, -}: PropsWithChildren) => JSX.Element; +export const SidebarSubmenu: (props: SidebarSubmenuProps) => JSX.Element; // @public export const SidebarSubmenuItem: ( @@ -2349,6 +2394,33 @@ export function useQueryParamState( // @public (undocumented) export function UserIcon(props: IconComponentProps): JSX.Element; +// @public +export class UserIdentity implements IdentityApi { + static create(options: { + identity: BackstageUserIdentity; + authApi: ProfileInfoApi & BackstageIdentityApi & SessionApi; + profile?: ProfileInfo; + }): IdentityApi; + static createGuest(): IdentityApi; + static fromLegacy(result: SignInResult): IdentityApi; + // (undocumented) + getBackstageIdentity(): Promise; + // (undocumented) + getCredentials(): Promise<{ + token?: string | undefined; + }>; + // (undocumented) + getIdToken(): Promise; + // (undocumented) + getProfile(): ProfileInfo; + // (undocumented) + getProfileInfo(): Promise; + // (undocumented) + getUserId(): string; + // (undocumented) + signOut(): Promise; +} + // 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) diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 80bfe64629..f47335fce8 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.7.6", + "version": "0.8.0", "private": false, "publishConfig": { "access": "public", @@ -30,18 +30,17 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.5", "@backstage/theme": "^0.2.14", "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", + "ansi-regex": "^5.0.1", "classnames": "^2.2.6", - "clsx": "^1.1.0", "d3-selection": "^3.0.0", "d3-shape": "^3.0.0", "d3-zoom": "^3.0.0", @@ -53,8 +52,6 @@ "prop-types": "^15.7.2", "qs": "^6.9.4", "rc-progress": "^3.0.0", - "react": "^16.12.0", - "react-dom": "^16.12.0", "react-helmet": "6.1.0", "react-hook-form": "^7.12.2", "react-markdown": "^7.0.1", @@ -64,13 +61,20 @@ "react-syntax-highlighter": "^15.4.3", "react-text-truncate": "^0.16.0", "react-use": "^17.2.4", + "react-virtualized-auto-sizer": "^1.0.6", + "react-window": "^1.8.6", "remark-gfm": "^2.0.0", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/core-app-api": "^0.1.24", - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", @@ -79,12 +83,15 @@ "@types/d3-selection": "^3.0.1", "@types/d3-shape": "^3.0.1", "@types/d3-zoom": "^3.0.1", + "@types/ansi-regex": "^5.0.0", "@types/dagre": "^0.7.44", "@types/google-protobuf": "^3.7.2", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", "@types/react-helmet": "^6.1.0", "@types/react-syntax-highlighter": "^13.5.2", + "@types/react-virtualized-auto-sizer": "^1.0.1", + "@types/react-window": "^1.8.5", "@types/zen-observable": "^0.8.0" }, "files": [ diff --git a/packages/core-components/src/components/CopyTextButton/CopyTextButton.test.tsx b/packages/core-components/src/components/CopyTextButton/CopyTextButton.test.tsx index a9532dd79b..ecb784f951 100644 --- a/packages/core-components/src/components/CopyTextButton/CopyTextButton.test.tsx +++ b/packages/core-components/src/components/CopyTextButton/CopyTextButton.test.tsx @@ -15,8 +15,7 @@ */ import React from 'react'; -import { fireEvent } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { act, fireEvent } from '@testing-library/react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { CopyTextButton } from './CopyTextButton'; import { errorApiRef } from '@backstage/core-plugin-api'; diff --git a/packages/core-components/src/components/LogViewer/AnsiProcessor.test.ts b/packages/core-components/src/components/LogViewer/AnsiProcessor.test.ts new file mode 100644 index 0000000000..e957b28b7c --- /dev/null +++ b/packages/core-components/src/components/LogViewer/AnsiProcessor.test.ts @@ -0,0 +1,233 @@ +/* + * 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 { AnsiProcessor } from './AnsiProcessor'; + +describe('AnsiProcessor', () => { + it('should process a single line', () => { + const processor = new AnsiProcessor(); + expect(processor.process('foo\x1b[31mbar\x1b[39mbaz')).toEqual([ + { + chunks: [ + { + text: 'foo', + modifiers: {}, + }, + { + text: 'bar', + modifiers: { foreground: 'red' }, + }, + { + text: 'baz', + modifiers: {}, + }, + ], + text: 'foobarbaz', + lineNumber: 1, + }, + ]); + + expect(processor.process(`foo bar: baz`)).toEqual([ + { + chunks: [ + { + text: 'foo ', + modifiers: {}, + }, + { + text: 'bar', + modifiers: { foreground: 'green' }, + }, + { + text: ': baz', + modifiers: {}, + }, + ], + text: 'foo bar: baz', + lineNumber: 1, + }, + ]); + }); + + it('should process multiple lines', () => { + const processor = new AnsiProcessor(); + expect( + processor.process(` +a\x1b[34mb\x1b[39mc +x\x1b[44my\x1b[49mz +`), + ).toEqual([ + { chunks: [{ text: '', modifiers: {} }], text: '', lineNumber: 1 }, + { + chunks: [ + { + text: 'a', + modifiers: {}, + }, + { + text: 'b', + modifiers: { foreground: 'blue' }, + }, + { + text: 'c', + modifiers: {}, + }, + ], + text: 'abc', + lineNumber: 2, + }, + { + chunks: [ + { + text: 'x', + modifiers: {}, + }, + { + text: 'y', + modifiers: { background: 'blue' }, + }, + { + text: 'z', + modifiers: {}, + }, + ], + text: 'xyz', + lineNumber: 3, + }, + { chunks: [{ text: '', modifiers: {} }], text: '', lineNumber: 4 }, + ]); + }); + + it('should carry state across lines', () => { + const processor = new AnsiProcessor(); + expect( + processor.process(` +a\x1b[45mb\x1b[35mc +x\x1b[39my\x1b[49mz`), + ).toEqual([ + { chunks: [{ text: '', modifiers: {} }], text: '', lineNumber: 1 }, + { + chunks: [ + { + text: 'a', + modifiers: {}, + }, + { + text: 'b', + modifiers: { background: 'magenta' }, + }, + { + text: 'c', + modifiers: { foreground: 'magenta', background: 'magenta' }, + }, + ], + text: 'abc', + lineNumber: 2, + }, + { + chunks: [ + { + text: 'x', + modifiers: { foreground: 'magenta', background: 'magenta' }, + }, + { + text: 'y', + modifiers: { background: 'magenta' }, + }, + { + text: 'z', + modifiers: {}, + }, + ], + text: 'xyz', + lineNumber: 3, + }, + ]); + }); + + it('should carry forward state when appending lines', () => { + const processor = new AnsiProcessor(); + const out1 = processor.process(` +a\x1b[36mb\x1b[3mc`); + expect(out1).toEqual([ + { chunks: [{ text: '', modifiers: {} }], text: '', lineNumber: 1 }, + { + chunks: [ + { + text: 'a', + modifiers: {}, + }, + { + text: 'b', + modifiers: { foreground: 'cyan' }, + }, + { + text: 'c', + modifiers: { foreground: 'cyan', italic: true }, + }, + ], + text: 'abc', + lineNumber: 2, + }, + ]); + + const out2 = processor.process(` +a\x1b[36mb\x1b[3mc +x\x1b[39my\x1b[23mz`); + expect(out2).toEqual([ + { chunks: [{ text: '', modifiers: {} }], text: '', lineNumber: 1 }, + { + chunks: [ + { + text: 'a', + modifiers: {}, + }, + { + text: 'b', + modifiers: { foreground: 'cyan' }, + }, + { + text: 'c', + modifiers: { foreground: 'cyan', italic: true }, + }, + ], + text: 'abc', + lineNumber: 2, + }, + { + chunks: [ + { + text: 'x', + modifiers: { foreground: 'cyan', italic: true }, + }, + { + text: 'y', + modifiers: { italic: true }, + }, + { + text: 'z', + modifiers: {}, + }, + ], + text: 'xyz', + lineNumber: 3, + }, + ]); + + // Verifies that we appended rather than reprocessed + expect(out1[0]).toBe(out2[0]); + }); +}); diff --git a/packages/core-components/src/components/LogViewer/AnsiProcessor.ts b/packages/core-components/src/components/LogViewer/AnsiProcessor.ts new file mode 100644 index 0000000000..d0f835a70e --- /dev/null +++ b/packages/core-components/src/components/LogViewer/AnsiProcessor.ts @@ -0,0 +1,216 @@ +/* + * 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 ansiRegexMaker from 'ansi-regex'; + +const ansiRegex = ansiRegexMaker(); +const newlineRegex = /\n\r?/g; + +// A mapping of how each escape code changes the modifiers +const codeModifiers = Object.fromEntries( + Object.entries({ + 1: m => ({ ...m, bold: true }), + 3: m => ({ ...m, italic: true }), + 4: m => ({ ...m, underline: true }), + 22: ({ bold: _, ...m }) => m, + 23: ({ italic: _, ...m }) => m, + 24: ({ underline: _, ...m }) => m, + 30: m => ({ ...m, foreground: 'black' }), + 31: m => ({ ...m, foreground: 'red' }), + 32: m => ({ ...m, foreground: 'green' }), + 33: m => ({ ...m, foreground: 'yellow' }), + 34: m => ({ ...m, foreground: 'blue' }), + 35: m => ({ ...m, foreground: 'magenta' }), + 36: m => ({ ...m, foreground: 'cyan' }), + 37: m => ({ ...m, foreground: 'white' }), + 39: ({ foreground: _, ...m }) => m, + 90: m => ({ ...m, foreground: 'grey' }), + 40: m => ({ ...m, background: 'black' }), + 41: m => ({ ...m, background: 'red' }), + 42: m => ({ ...m, background: 'green' }), + 43: m => ({ ...m, background: 'yellow' }), + 44: m => ({ ...m, background: 'blue' }), + 45: m => ({ ...m, background: 'magenta' }), + 46: m => ({ ...m, background: 'cyan' }), + 47: m => ({ ...m, background: 'white' }), + 49: ({ background: _, ...m }) => m, + } as Record ChunkModifiers>).map( + ([code, modifier]) => [`\x1b[${code}m`, modifier], + ), +); + +export type AnsiColor = + | 'black' + | 'red' + | 'green' + | 'yellow' + | 'blue' + | 'magenta' + | 'cyan' + | 'white' + | 'grey'; + +export interface ChunkModifiers { + foreground?: AnsiColor; + background?: AnsiColor; + bold?: boolean; + italic?: boolean; + underline?: boolean; +} + +export interface AnsiChunk { + text: string; + modifiers: ChunkModifiers; +} + +export class AnsiLine { + text: string; + + constructor( + readonly lineNumber: number = 1, + readonly chunks: AnsiChunk[] = [], + ) { + this.text = chunks + .map(c => c.text) + .join('') + .toLocaleLowerCase('en-US'); + } + + lastChunk(): AnsiChunk | undefined { + return this.chunks[this.chunks.length - 1]; + } + + replaceLastChunk(newChunks?: AnsiChunk[]) { + if (newChunks) { + this.chunks.splice(this.chunks.length - 1, 1, ...newChunks); + this.text = this.chunks + .map(c => c.text) + .join('') + .toLocaleLowerCase('en-US'); + } + } +} + +export class AnsiProcessor { + private text: string = ''; + private lines: AnsiLine[] = []; + + /** + * Processes a chunk of text while keeping internal state that optimizes + * subsequent processing that appends to the text. + */ + process(text: string): AnsiLine[] { + if (this.text === text) { + return this.lines; + } + + if (text.startsWith(this.text)) { + const lastLineIndex = this.lines.length > 0 ? this.lines.length - 1 : 0; + const lastLine = this.lines[lastLineIndex] ?? new AnsiLine(); + const lastChunk = lastLine.lastChunk(); + + const newLines = this.processLines( + (lastChunk?.text ?? '') + text.slice(this.text.length), + lastChunk?.modifiers, + lastLine?.lineNumber, + ); + lastLine.replaceLastChunk(newLines[0]?.chunks); + + this.lines[lastLineIndex] = lastLine; + this.lines.push(...newLines.slice(1)); + } else { + this.lines = this.processLines(text); + } + this.text = text; + + return this.lines; + } + + // Split a chunk of text up into lines and process each line individually + private processLines = ( + text: string, + modifiers: ChunkModifiers = {}, + startingLineNumber: number = 1, + ): AnsiLine[] => { + const lines: AnsiLine[] = []; + + let currentModifiers = modifiers; + let currentLineNumber = startingLineNumber; + + let prevIndex = 0; + newlineRegex.lastIndex = 0; + for (;;) { + const match = newlineRegex.exec(text); + if (!match) { + const chunks = this.processText( + text.slice(prevIndex), + currentModifiers, + ); + lines.push(new AnsiLine(currentLineNumber, chunks)); + return lines; + } + + const line = text.slice(prevIndex, match.index); + prevIndex = match.index + match[0].length; + + const chunks = this.processText(line, currentModifiers); + lines.push(new AnsiLine(currentLineNumber, chunks)); + + // Modifiers that are active in the last chunk are carried over to the next line + currentModifiers = + chunks[chunks.length - 1].modifiers ?? currentModifiers; + currentLineNumber += 1; + } + }; + + // Processing of a one individual text chunk + private processText = ( + fullText: string, + modifiers: ChunkModifiers, + ): AnsiChunk[] => { + const chunks: AnsiChunk[] = []; + + let currentModifiers = modifiers; + + let prevIndex = 0; + ansiRegex.lastIndex = 0; + for (;;) { + const match = ansiRegex.exec(fullText); + if (!match) { + chunks.push({ + text: fullText.slice(prevIndex), + modifiers: currentModifiers, + }); + return chunks; + } + + const text = fullText.slice(prevIndex, match.index); + chunks.push({ text, modifiers: currentModifiers }); + + // For every escape code that we encounter we keep track of where the + // next chunk of text starts, and what modifiers it has + prevIndex = match.index + match[0].length; + currentModifiers = this.processCode(match[0], currentModifiers); + } + }; + + private processCode = ( + code: string, + modifiers: ChunkModifiers, + ): ChunkModifiers => { + return codeModifiers[code]?.(modifiers) ?? modifiers; + }; +} diff --git a/packages/core-components/src/components/LogViewer/LogLine.test.tsx b/packages/core-components/src/components/LogViewer/LogLine.test.tsx new file mode 100644 index 0000000000..c5fd6e39ca --- /dev/null +++ b/packages/core-components/src/components/LogViewer/LogLine.test.tsx @@ -0,0 +1,356 @@ +/* + * 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 { AnsiLine, ChunkModifiers } from './AnsiProcessor'; +import { + calculateHighlightedChunks, + findSearchResults, + getModifierClasses, +} from './LogLine'; + +describe('getModifierClasses', () => { + const classes = { + modifierBold: 'bold', + modifierItalic: 'italic', + modifierUnderline: 'underline', + modifierForegroundBlack: 'black', + modifierForegroundRed: 'red', + modifierForegroundGreen: 'green', + modifierForegroundYellow: 'yellow', + modifierForegroundBlue: 'blue', + modifierForegroundMagenta: 'magenta', + modifierForegroundCyan: 'cyan', + modifierForegroundWhite: 'white', + modifierForegroundGrey: 'grey', + modifierBackgroundBlack: 'bg-black', + modifierBackgroundRed: 'bg-red', + modifierBackgroundGreen: 'bg-green', + modifierBackgroundYellow: 'bg-yellow', + modifierBackgroundBlue: 'bg-blue', + modifierBackgroundMagenta: 'bg-magenta', + modifierBackgroundCyan: 'bg-cyan', + modifierBackgroundWhite: 'bg-white', + modifierBackgroundGrey: 'bg-grey', + }; + const curried = (modifiers: ChunkModifiers) => + getModifierClasses( + classes as Parameters[0], + modifiers, + ); + + it('should transform modifiers to classes', () => { + expect(curried({})).toEqual(undefined); + expect(curried({ bold: true })).toEqual('bold'); + expect(curried({ italic: true })).toEqual('italic'); + expect(curried({ underline: true })).toEqual('underline'); + expect(curried({ foreground: 'black' })).toEqual('black'); + expect(curried({ background: 'black' })).toEqual('bg-black'); + expect( + curried({ + bold: true, + italic: true, + underline: true, + foreground: 'red', + background: 'red', + }), + ).toEqual('bold italic underline red bg-red'); + }); +}); + +describe('findSearchResults', () => { + it('should not return results if there is no match', () => { + expect(findSearchResults('Foo', 'Bar')).toEqual(undefined); + expect(findSearchResults('Foo Bar', 'oof')).toEqual(undefined); + expect(findSearchResults('Foo Bar', '')).toEqual(undefined); + expect(findSearchResults('', '')).toEqual(undefined); + expect(findSearchResults('', 'Foo')).toEqual(undefined); + }); + + it('should find result indices', () => { + expect(findSearchResults('Foo', 'Foo')).toEqual([{ start: 0, end: 3 }]); + expect(findSearchResults('Foo', 'o')).toEqual([ + { start: 1, end: 2 }, + { start: 2, end: 3 }, + ]); + expect(findSearchResults('FooBarBaz', 'Bar')).toEqual([ + { start: 3, end: 6 }, + ]); + expect(findSearchResults('Foo Bar Baz', ' ')).toEqual([ + { start: 3, end: 4 }, + { start: 7, end: 8 }, + ]); + expect(findSearchResults('FooBarBazBarFoo', 'Bar')).toEqual([ + { start: 3, end: 6 }, + { start: 9, end: 12 }, + ]); + expect(findSearchResults('FooBarBazBarFoo', 'Foo')).toEqual([ + { start: 0, end: 3 }, + { start: 12, end: 15 }, + ]); + }); + + it('should not overlap search results', () => { + expect(findSearchResults('aaa', 'aa')).toEqual([{ start: 0, end: 2 }]); + expect(findSearchResults('aaaa', 'aa')).toEqual([ + { start: 0, end: 2 }, + { start: 2, end: 4 }, + ]); + expect(findSearchResults('aaaaa', 'aa')).toEqual([ + { start: 0, end: 2 }, + { start: 2, end: 4 }, + ]); + }); +}); + +describe('calculateHighlightedChunks', () => { + it('should pass through chunks if there are no results', () => { + const chunks = [{ text: 'Foo', modifiers: {} }]; + const line = new AnsiLine(0, chunks); + expect(calculateHighlightedChunks(line, 'bar')).toBe(chunks); + }); + + it('should highlight one result from plain text', () => { + const line = new AnsiLine(0, [{ text: 'FooBarBaz', modifiers: {} }]); + expect(calculateHighlightedChunks(line, 'foo')).toEqual([ + { + text: 'Foo', + modifiers: {}, + highlight: 0, + }, + { + text: 'BarBaz', + modifiers: {}, + }, + ]); + expect(calculateHighlightedChunks(line, 'bar')).toEqual([ + { + text: 'Foo', + modifiers: {}, + }, + { + text: 'Bar', + modifiers: {}, + highlight: 0, + }, + { + text: 'Baz', + modifiers: {}, + }, + ]); + expect(calculateHighlightedChunks(line, 'baz')).toEqual([ + { + text: 'FooBar', + modifiers: {}, + }, + { + text: 'Baz', + modifiers: {}, + highlight: 0, + }, + ]); + }); + + it('should highlight multiple results from plain text', () => { + const line = new AnsiLine(0, [ + { text: 'FooBarBazBazBarFoo', modifiers: {} }, + ]); + expect(calculateHighlightedChunks(line, 'foo')).toEqual([ + { + text: 'Foo', + modifiers: {}, + highlight: 0, + }, + { + text: 'BarBazBazBar', + modifiers: {}, + }, + { + text: 'Foo', + modifiers: {}, + highlight: 1, + }, + ]); + expect(calculateHighlightedChunks(line, 'bar')).toEqual([ + { + text: 'Foo', + modifiers: {}, + }, + { + text: 'Bar', + modifiers: {}, + highlight: 0, + }, + { + text: 'BazBaz', + modifiers: {}, + }, + { + text: 'Bar', + modifiers: {}, + highlight: 1, + }, + { + text: 'Foo', + modifiers: {}, + }, + ]); + expect(calculateHighlightedChunks(line, 'baz')).toEqual([ + { + text: 'FooBar', + modifiers: {}, + }, + { + text: 'Baz', + modifiers: {}, + highlight: 0, + }, + { + text: 'Baz', + modifiers: {}, + highlight: 1, + }, + { + text: 'BarFoo', + modifiers: {}, + }, + ]); + }); + + it('should forward modifiers to result', () => { + const line = new AnsiLine(0, [ + { text: 'FooBarBazBazBarFoo', modifiers: { bold: true } }, + ]); + expect(calculateHighlightedChunks(line, 'foo')).toEqual([ + { + text: 'Foo', + modifiers: { bold: true }, + highlight: 0, + }, + { + text: 'BarBazBazBar', + modifiers: { bold: true }, + }, + { + text: 'Foo', + modifiers: { bold: true }, + highlight: 1, + }, + ]); + }); + + it('should highlight full chunks', () => { + const line = new AnsiLine(0, [ + { text: 'Foo', modifiers: { bold: true } }, + { text: 'BarBaz', modifiers: { bold: true } }, + { text: 'BazBar', modifiers: { italic: true } }, + { text: 'Foo', modifiers: { italic: true } }, + ]); + expect(calculateHighlightedChunks(line, 'foo')).toEqual([ + { + text: 'Foo', + modifiers: { bold: true }, + highlight: 0, + }, + { + text: 'BarBaz', + modifiers: { bold: true }, + }, + { + text: 'BazBar', + modifiers: { italic: true }, + }, + { + text: 'Foo', + modifiers: { italic: true }, + highlight: 1, + }, + ]); + }); + + it('should highlight partial chunks', () => { + const line = new AnsiLine(0, [ + { text: 'Fo', modifiers: { bold: true } }, + { text: 'oFooFo', modifiers: {} }, + { text: 'oBarBaz', modifiers: { italic: true } }, + { text: 'Foo', modifiers: { foreground: 'blue' } }, + { text: 'FooFoo', modifiers: { italic: true } }, + { text: 'F', modifiers: { bold: true } }, + { text: 'o', modifiers: {} }, + { text: 'o', modifiers: { bold: true } }, + ]); + expect(calculateHighlightedChunks(line, 'foo')).toEqual([ + { + text: 'Fo', + modifiers: { bold: true }, + highlight: 0, + }, + { + text: 'o', + modifiers: {}, + highlight: 0, + }, + { + text: 'Foo', + modifiers: {}, + highlight: 1, + }, + { + text: 'Fo', + modifiers: {}, + highlight: 2, + }, + { + text: 'o', + modifiers: { italic: true }, + highlight: 2, + }, + { + text: 'BarBaz', + modifiers: { italic: true }, + }, + { + text: 'Foo', + modifiers: { foreground: 'blue' }, + highlight: 3, + }, + { + text: 'Foo', + modifiers: { italic: true }, + highlight: 4, + }, + { + text: 'Foo', + modifiers: { italic: true }, + highlight: 5, + }, + { + text: 'F', + modifiers: { bold: true }, + highlight: 6, + }, + { + text: 'o', + modifiers: {}, + highlight: 6, + }, + { + text: 'o', + modifiers: { bold: true }, + highlight: 6, + }, + ]); + }); +}); diff --git a/packages/core-components/src/components/LogViewer/LogLine.tsx b/packages/core-components/src/components/LogViewer/LogLine.tsx new file mode 100644 index 0000000000..ed3396360e --- /dev/null +++ b/packages/core-components/src/components/LogViewer/LogLine.tsx @@ -0,0 +1,178 @@ +/* + * 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 React, { useMemo } from 'react'; +import { AnsiChunk, AnsiLine, ChunkModifiers } from './AnsiProcessor'; +import startCase from 'lodash/startCase'; +import classnames from 'classnames'; +import { useStyles } from './styles'; + +export function getModifierClasses( + classes: ReturnType, + modifiers: ChunkModifiers, +) { + const classNames = new Array(); + if (modifiers.bold) { + classNames.push(classes.modifierBold); + } + if (modifiers.italic) { + classNames.push(classes.modifierItalic); + } + if (modifiers.underline) { + classNames.push(classes.modifierUnderline); + } + if (modifiers.foreground) { + const key = `modifierForeground${startCase( + modifiers.foreground, + )}` as keyof typeof classes; + classNames.push(classes[key]); + } + if (modifiers.background) { + const key = `modifierBackground${startCase( + modifiers.background, + )}` as keyof typeof classes; + classNames.push(classes[key]); + } + return classNames.length > 0 ? classNames.join(' ') : undefined; +} + +export function findSearchResults(text: string, searchText: string) { + if (!searchText || !text.includes(searchText)) { + return undefined; + } + const searchResults = new Array<{ start: number; end: number }>(); + let offset = 0; + for (;;) { + const start = text.indexOf(searchText, offset); + if (start === -1) { + break; + } + const end = start + searchText.length; + searchResults.push({ start, end }); + offset = end; + } + return searchResults; +} + +export interface HighlightAnsiChunk extends AnsiChunk { + highlight?: number; +} + +export function calculateHighlightedChunks( + line: AnsiLine, + searchText: string, +): HighlightAnsiChunk[] { + const results = findSearchResults(line.text, searchText); + if (!results) { + return line.chunks; + } + + const chunks = new Array(); + + let lineOffset = 0; + let resultIndex = 0; + let result = results[resultIndex]; + for (const chunk of line.chunks) { + const { text, modifiers } = chunk; + if (!result || lineOffset + text.length < result.start) { + chunks.push(chunk); + lineOffset += text.length; + continue; + } + + let localOffset = 0; + while (result) { + const localStart = Math.max(result.start - lineOffset, 0); + if (localStart > text.length) { + break; // The next result is not in this chunk + } + + const localEnd = Math.min(result.end - lineOffset, text.length); + + const hasTextBeforeResult = localStart > localOffset; + if (hasTextBeforeResult) { + chunks.push({ text: text.slice(localOffset, localStart), modifiers }); + } + const hasResultText = localEnd > localStart; + if (hasResultText) { + chunks.push({ + modifiers, + highlight: resultIndex, + text: text.slice(localStart, localEnd), + }); + } + + localOffset = localEnd; + + const foundCompleteResult = result.end - lineOffset === localEnd; + if (foundCompleteResult) { + resultIndex += 1; + result = results[resultIndex]; + } else { + break; // The rest of the result is in the following chunks + } + } + + const hasTextAfterResult = localOffset < text.length; + if (hasTextAfterResult) { + chunks.push({ text: text.slice(localOffset), modifiers }); + } + + lineOffset += text.length; + } + + return chunks; +} + +export interface LogLineProps { + line: AnsiLine; + classes: ReturnType; + searchText: string; + highlightResultIndex?: number; +} + +export function LogLine({ + line, + classes, + searchText, + highlightResultIndex, +}: LogLineProps) { + const chunks = useMemo( + () => calculateHighlightedChunks(line, searchText), + [line, searchText], + ); + + const elements = useMemo( + () => + chunks.map(({ text, modifiers, highlight }, index) => ( + + {text} + + )), + [chunks, highlightResultIndex, classes], + ); + + return <>{elements}; +} diff --git a/packages/core-components/src/components/LogViewer/LogViewer.stories.tsx b/packages/core-components/src/components/LogViewer/LogViewer.stories.tsx new file mode 100644 index 0000000000..255e1d03b8 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/LogViewer.stories.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 React, { ComponentType } from 'react'; +import { wrapInTestApp } from '@backstage/test-utils'; +import { LogViewer } from './LogViewer'; + +export default { + title: 'Data Display/LogViewer', + component: LogViewer, + decorators: [(Story: ComponentType<{}>) => wrapInTestApp()], +}; + +const exampleLog = `Starting up task with 3 steps +Beginning step Fetch Skeleton + Template +info: Fetching template content from remote URL {"timestamp":"2021-12-03T15:47:11.625Z"} +info: Listing files and directories in template {"timestamp":"2021-12-03T15:47:12.797Z"} +info: Processing 33 template files/directories with input values {"component_id":"srnthsrthntrhsn","description":"rnthsrtnhssrthnrsthn","destination":{"host":"github.com","owner":"rtshnsrtmhrstmh","repo":"srtmhsrtmhrsthms"},"owner":"rstnhrstnhsrthn","timestamp":"2021-12-03T15:47:12.801Z"} +info: Writing file .editorconfig to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.816Z"} +info: Writing file .eslintignore to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.818Z"} +info: Writing file .eslintrc.js to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.820Z"} +info: Writing directory .github/ to template output path. {"timestamp":"2021-12-03T15:47:12.823Z"} +info: Writing file .gitignore to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.824Z"} +info: Writing file README.md to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.827Z"} +info: Writing file babel.config.js to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.829Z"} +info: Writing file catalog-info.yaml to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.831Z"} +info: Writing directory docs/ to template output path. {"timestamp":"2021-12-03T15:47:12.834Z"} +info: Writing file jest.config.js to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.836Z"} +info: Writing file mkdocs.yml to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.838Z"} +info: Writing file next-env.d.ts to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.841Z"} +info: Writing file next.config.js to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.844Z"} +info: Writing file package.json to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.845Z"} +info: Writing file prettier.config.js to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.848Z"} +info: Writing directory public/ to template output path. {"timestamp":"2021-12-03T15:47:12.849Z"} +info: Writing directory src/ to template output path. {"timestamp":"2021-12-03T15:47:12.850Z"} +info: Writing file tsconfig.json to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.851Z"} +info: Writing directory .github/workflows/ to template output path. {"timestamp":"2021-12-03T15:47:12.853Z"} +info: Writing file docs/index.md to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.854Z"} +info: Writing directory public/static/ to template output path. {"timestamp":"2021-12-03T15:47:12.857Z"} +info: Writing directory src/__tests__/ to template output path. {"timestamp":"2021-12-03T15:47:12.858Z"} +info: Writing directory src/components/ to template output path. {"timestamp":"2021-12-03T15:47:12.858Z"} +info: Writing directory src/pages/ to template output path. {"timestamp":"2021-12-03T15:47:12.859Z"} +info: Copying file/directory .github/workflows/build.yml without processing. {"timestamp":"2021-12-03T15:47:12.859Z"} +info: Writing file .github/workflows/build.yml to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.860Z"} +info: Writing file public/static/fonts.css to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.861Z"} +info: Writing file src/components/Header.tsx to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.863Z"} +info: Writing file src/__tests__/index.test.tsx to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.865Z"} +info: Writing file src/pages/_app.tsx to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.868Z"} +info: Writing file src/pages/_document.tsx to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.871Z"} +info: Writing directory src/pages/api/ to template output path. {"timestamp":"2021-12-03T15:47:12.873Z"} +info: Writing file src/pages/index.tsx to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.874Z"} +info: Writing file src/pages/api/ping.ts to template output path with mode 33188. {"timestamp":"2021-12-03T15:47:12.877Z"} +info: Template result written to /var/folders/k6/9s7hd6w17115xlgwnsp0wsbr0000gn/T/5c9f8584-fded-4741-b6ef-46d94ff2cbdb {"timestamp":"2021-12-03T15:47:12.878Z"} +Finished step Fetch Skeleton + Template +Beginning step Publish +HttpError: Not Found + at /Users/patriko/dev/backstage/node_modules/@octokit/request/dist-node/index.js:86:21 + at runMicrotasks () + at processTicksAndRejections (internal/process/task_queues.js:95:5) + at async Object.handler (webpack-internal:///../../plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts:156:20) + at async HandlebarsWorkflowRunner.execute (webpack-internal:///../../plugins/scaffolder-backend/src/scaffolder/tasks/HandlebarsWorkflowRunner.ts:254:11) + at async TaskWorker.runOneTask (webpack-internal:///../../plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts:110:13) + at async eval (webpack-internal:///../../plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts:100:9) +Run completed with status: failed`; + +export const ExampleLogViewer = () => ( +
+ +
+); diff --git a/packages/core-components/src/components/LogViewer/LogViewer.tsx b/packages/core-components/src/components/LogViewer/LogViewer.tsx new file mode 100644 index 0000000000..bdb3973015 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/LogViewer.tsx @@ -0,0 +1,64 @@ +/* + * 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 React, { lazy, Suspense } from 'react'; +import { useApp } from '@backstage/core-plugin-api'; + +const RealLogViewer = lazy(() => + import('./RealLogViewer').then(m => ({ default: m.RealLogViewer })), +); + +/** + * The properties for the LogViewer component. + * + * @public + */ +export interface LogViewerProps { + /** + * The text of the logs to display. + * + * The LogViewer component is optimized for appending content at the end of the text. + */ + text: string; + /** + * Styling overrides for classes within the LogViewer component. + */ + classes?: { + root?: string; + }; +} + +/** + * A component that displays logs in a scrollable text area. + * + * The LogViewer has support for search and filtering, as well as displaying + * text content with ANSI color escape codes. + * + * Since the LogViewer uses windowing to avoid rendering all contents at once, the + * log is sized automatically to fill the available vertical space. This means + * it may often be needed to wrap the LogViewer in a container that provides it + * with a fixed amount of space. + * + * @public + */ +export function LogViewer(props: LogViewerProps) { + const { Progress } = useApp().getComponents(); + return ( + }> + + + ); +} diff --git a/packages/core-components/src/components/LogViewer/LogViewerControls.tsx b/packages/core-components/src/components/LogViewer/LogViewerControls.tsx new file mode 100644 index 0000000000..4d3baae68d --- /dev/null +++ b/packages/core-components/src/components/LogViewer/LogViewerControls.tsx @@ -0,0 +1,74 @@ +/* + * 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 React from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; +import ChevronRightIcon from '@material-ui/icons/ChevronRight'; +import FilterListIcon from '@material-ui/icons/FilterList'; +import { LogViewerSearch } from './useLogViewerSearch'; + +export interface LogViewerControlsProps extends LogViewerSearch {} + +export function LogViewerControls(props: LogViewerControlsProps) { + const { resultCount, resultIndexStep, toggleShouldFilter } = props; + const resultIndex = props.resultIndex ?? 0; + + const handleKeyPress = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + if (event.metaKey || event.ctrlKey || event.altKey) { + toggleShouldFilter(); + } else { + resultIndexStep(event.shiftKey); + } + } + }; + + return ( + <> + {resultCount !== undefined && ( + <> + resultIndexStep(true)}> + + + + {Math.min(resultIndex + 1, resultCount)}/{resultCount} + + resultIndexStep()}> + + + + )} + props.setSearchInput(e.target.value)} + /> + + {props.shouldFilter ? ( + + ) : ( + + )} + + + ); +} diff --git a/packages/core-components/src/components/LogViewer/RealLogViewer.test.tsx b/packages/core-components/src/components/LogViewer/RealLogViewer.test.tsx new file mode 100644 index 0000000000..8d5efb9724 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/RealLogViewer.test.tsx @@ -0,0 +1,79 @@ +/* + * 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 React, { ReactNode } from 'react'; +import UserEvent from '@testing-library/user-event'; +import { renderInTestApp } from '@backstage/test-utils'; +import { RealLogViewer } from './RealLogViewer'; +// eslint-disable-next-line import/no-extraneous-dependencies +import copyToClipboard from 'copy-to-clipboard'; + +// Used by useCopyToClipboard +jest.mock('copy-to-clipboard', () => ({ + __esModule: true, + default: jest.fn(), +})); + +// The inside needs mocking to render in jsdom +jest.mock('react-virtualized-auto-sizer', () => ({ + __esModule: true, + default: (props: { + children: (size: { width: number; height: number }) => ReactNode; + }) => <>{props.children({ width: 400, height: 200 })}, +})); + +const testText = `Some Log Line +Derp +Foo + +Foo Foo +Wat`; + +describe('RealLogViewer', () => { + it('should render text with search and filtering and copying', async () => { + const rendered = await renderInTestApp(); + expect(rendered.getByText('Derp')).toBeInTheDocument(); + expect(rendered.getByText('Foo Foo')).toBeInTheDocument(); + + UserEvent.tab(); + UserEvent.keyboard('Foo'); + + expect(rendered.getByText('1/3')).toBeInTheDocument(); + UserEvent.keyboard('{enter}'); + expect(rendered.getByText('2/3')).toBeInTheDocument(); + UserEvent.keyboard('{enter}'); + expect(rendered.getByText('3/3')).toBeInTheDocument(); + UserEvent.keyboard('{enter}'); + expect(rendered.getByText('1/3')).toBeInTheDocument(); + UserEvent.keyboard('{shift}{enter}{/shift}'); + expect(rendered.getByText('3/3')).toBeInTheDocument(); + + expect(rendered.queryByText('Some Log Line')).toBeInTheDocument(); + UserEvent.keyboard('{meta}{enter}{/meta}'); + expect(rendered.queryByText('Some Log Line')).not.toBeInTheDocument(); + UserEvent.keyboard('{meta}{enter}{/meta}'); + expect(rendered.queryByText('Some Log Line')).toBeInTheDocument(); + + // Tab down to line #2 and click + UserEvent.tab(); + UserEvent.tab(); + UserEvent.tab(); + UserEvent.click(document.activeElement!); + UserEvent.click(rendered.getByTestId('copy-button')); + + expect(copyToClipboard).toHaveBeenCalledWith('Derp'); + }); +}); diff --git a/packages/core-components/src/components/LogViewer/RealLogViewer.tsx b/packages/core-components/src/components/LogViewer/RealLogViewer.tsx new file mode 100644 index 0000000000..cd30e96c92 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/RealLogViewer.tsx @@ -0,0 +1,124 @@ +/* + * 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 React, { useEffect, useMemo, useRef } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import CopyIcon from '@material-ui/icons/FileCopy'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { FixedSizeList } from 'react-window'; +import { AnsiProcessor } from './AnsiProcessor'; +import { HEADER_SIZE, useStyles } from './styles'; +import classnames from 'classnames'; +import { LogLine } from './LogLine'; +import { LogViewerControls } from './LogViewerControls'; +import { useLogViewerSearch } from './useLogViewerSearch'; +import { useLogViewerSelection } from './useLogViewerSelection'; + +export interface RealLogViewerProps { + text: string; + classes?: { root?: string }; +} + +export function RealLogViewer(props: RealLogViewerProps) { + const classes = useStyles({ classes: props.classes }); + const listRef = useRef(null); + + // The processor keeps state that optimizes appending to the text + const processor = useMemo(() => new AnsiProcessor(), []); + const lines = processor.process(props.text); + + const search = useLogViewerSearch(lines); + const selection = useLogViewerSelection(lines); + + useEffect(() => { + if (search.resultLine !== undefined && listRef.current) { + listRef.current.scrollToItem(search.resultLine - 1, 'center'); + } + }, [search.resultLine]); + + const handleSelectLine = ( + line: number, + event: { shiftKey: boolean; preventDefault: () => void }, + ) => { + event.preventDefault(); + selection.setSelection(line, event.shiftKey); + }; + + return ( + + {({ height, width }) => ( +
+
+ +
+ + {({ index, style, data }) => { + const line = data[index]; + const { lineNumber } = line; + return ( +
+ {selection.shouldShowButton(lineNumber) && ( + selection.copySelection()} + > + + + )} + handleSelectLine(lineNumber, event)} + onKeyPress={event => handleSelectLine(lineNumber, event)} + > + {lineNumber} + + +
+ ); + }} +
+
+ )} +
+ ); +} diff --git a/packages/core-components/src/components/LogViewer/index.ts b/packages/core-components/src/components/LogViewer/index.ts new file mode 100644 index 0000000000..f99695f163 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/index.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export { LogViewer } from './LogViewer'; +export type { LogViewerProps } from './LogViewer'; +export type { LogViewerClassKey } from './styles'; diff --git a/packages/core-components/src/components/LogViewer/styles.ts b/packages/core-components/src/components/LogViewer/styles.ts new file mode 100644 index 0000000000..2028809543 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/styles.ts @@ -0,0 +1,168 @@ +/* + * 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 { alpha, makeStyles } from '@material-ui/core/styles'; +import * as colors from '@material-ui/core/colors'; + +export const HEADER_SIZE = 40; + +/** @public Class keys for overriding LogViewer styles */ +export type LogViewerClassKey = + | 'root' + | 'header' + | 'log' + | 'line' + | 'lineSelected' + | 'lineCopyButton' + | 'lineNumber' + | 'textHighlight' + | 'textSelectedHighlight' + | 'modifierBold' + | 'modifierItalic' + | 'modifierUnderline' + | 'modifierForegroundBlack' + | 'modifierForegroundRed' + | 'modifierForegroundGreen' + | 'modifierForegroundYellow' + | 'modifierForegroundBlue' + | 'modifierForegroundMagenta' + | 'modifierForegroundCyan' + | 'modifierForegroundWhite' + | 'modifierForegroundGrey' + | 'modifierBackgroundBlack' + | 'modifierBackgroundRed' + | 'modifierBackgroundGreen' + | 'modifierBackgroundYellow' + | 'modifierBackgroundBlue' + | 'modifierBackgroundMagenta' + | 'modifierBackgroundCyan' + | 'modifierBackgroundWhite' + | 'modifierBackgroundGrey'; + +export const useStyles = makeStyles( + theme => ({ + root: { + background: theme.palette.background.paper, + }, + header: { + height: HEADER_SIZE, + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + }, + log: { + fontFamily: '"Monaco", monospace', + fontSize: theme.typography.pxToRem(12), + }, + line: { + position: 'relative', + whiteSpace: 'pre', + + '&:hover': { + background: theme.palette.action.hover, + }, + }, + lineSelected: { + background: theme.palette.action.selected, + + '&:hover': { + background: theme.palette.action.selected, + }, + }, + lineCopyButton: { + position: 'absolute', + paddingTop: 0, + paddingBottom: 0, + }, + lineNumber: { + display: 'inline-block', + textAlign: 'end', + width: 60, + marginRight: theme.spacing(1), + cursor: 'pointer', + }, + textHighlight: { + background: alpha(theme.palette.info.main, 0.15), + }, + textSelectedHighlight: { + background: alpha(theme.palette.info.main, 0.4), + }, + modifierBold: { + fontWeight: theme.typography.fontWeightBold, + }, + modifierItalic: { + fontStyle: 'italic', + }, + modifierUnderline: { + textDecoration: 'underline', + }, + modifierForegroundBlack: { + color: colors.common.black, + }, + modifierForegroundRed: { + color: colors.red[500], + }, + modifierForegroundGreen: { + color: colors.green[500], + }, + modifierForegroundYellow: { + color: colors.yellow[500], + }, + modifierForegroundBlue: { + color: colors.blue[500], + }, + modifierForegroundMagenta: { + color: colors.purple[500], + }, + modifierForegroundCyan: { + color: colors.cyan[500], + }, + modifierForegroundWhite: { + color: colors.common.white, + }, + modifierForegroundGrey: { + color: colors.grey[500], + }, + modifierBackgroundBlack: { + background: colors.common.black, + }, + modifierBackgroundRed: { + background: colors.red[500], + }, + modifierBackgroundGreen: { + background: colors.green[500], + }, + modifierBackgroundYellow: { + background: colors.yellow[500], + }, + modifierBackgroundBlue: { + background: colors.blue[500], + }, + modifierBackgroundMagenta: { + background: colors.purple[500], + }, + modifierBackgroundCyan: { + background: colors.cyan[500], + }, + modifierBackgroundWhite: { + background: colors.common.white, + }, + modifierBackgroundGrey: { + background: colors.grey[500], + }, + }), + { name: 'BackstageLogViewer' }, +); diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx new file mode 100644 index 0000000000..a64f22765b --- /dev/null +++ b/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx @@ -0,0 +1,221 @@ +/* + * 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 { act, renderHook } from '@testing-library/react-hooks'; +import { applySearchFilter, useLogViewerSearch } from './useLogViewerSearch'; +import { AnsiLine } from './AnsiProcessor'; + +const lines = [ + new AnsiLine(1, [{ text: 'FooBar', modifiers: {} }]), + new AnsiLine(2, [{ text: 'Baz', modifiers: {} }]), + new AnsiLine(3, [{ text: 'FooBarFoo', modifiers: {} }]), + new AnsiLine(4, [{ text: 'Baz', modifiers: {} }]), + new AnsiLine(5, [{ text: 'BazFoo', modifiers: {} }]), + new AnsiLine(6, [{ text: 'FooFooFoo', modifiers: {} }]), + new AnsiLine(7, [{ text: '', modifiers: {} }]), + new AnsiLine(8, [{ text: 'Bar', modifiers: {} }]), +]; + +describe('applySearchFilter', () => { + it('should find search results', () => { + expect(applySearchFilter(lines, '')).toEqual({ + lines: lines, + results: undefined, + }); + expect(applySearchFilter(lines, 'foo')).toEqual({ + lines: [lines[0], lines[2], lines[4], lines[5]], + results: [ + { lineNumber: 1, lineIndex: 0 }, + { lineNumber: 3, lineIndex: 0 }, + { lineNumber: 3, lineIndex: 1 }, + { lineNumber: 5, lineIndex: 0 }, + { lineNumber: 6, lineIndex: 0 }, + { lineNumber: 6, lineIndex: 1 }, + { lineNumber: 6, lineIndex: 2 }, + ], + }); + expect(applySearchFilter(lines, 'bar')).toEqual({ + lines: [lines[0], lines[2], lines[7]], + results: [ + { lineNumber: 1, lineIndex: 0 }, + { lineNumber: 3, lineIndex: 0 }, + { lineNumber: 8, lineIndex: 0 }, + ], + }); + expect(applySearchFilter(lines, 'baz')).toEqual({ + lines: [lines[1], lines[3], lines[4]], + results: [ + { lineNumber: 2, lineIndex: 0 }, + { lineNumber: 4, lineIndex: 0 }, + { lineNumber: 5, lineIndex: 0 }, + ], + }); + }); +}); + +describe('useLogViewerSearch', () => { + it('should provide search state', () => { + const rendered = renderHook(() => useLogViewerSearch(lines)); + expect(rendered.result.current).toMatchObject({ + lines, + searchText: '', + shouldFilter: false, + resultCount: undefined, + resultIndex: 0, + resultLine: undefined, + resultLineIndex: undefined, + }); + + rendered.result.current.resultIndexStep(); + expect(rendered.result.current).toMatchObject({ + lines, + searchText: '', + shouldFilter: false, + resultCount: undefined, + resultIndex: 0, + resultLine: undefined, + resultLineIndex: undefined, + }); + + act(() => rendered.result.current.toggleShouldFilter()); + expect(rendered.result.current).toMatchObject({ + lines, + searchText: '', + shouldFilter: true, + resultCount: undefined, + resultIndex: 0, + resultLine: undefined, + resultLineIndex: undefined, + }); + + act(() => rendered.result.current.setSearchInput('BAR')); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[7]], + searchInput: 'BAR', + searchText: 'bar', + shouldFilter: true, + resultCount: 3, + resultIndex: 0, + resultLine: 1, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[7]], + resultIndex: 1, + resultLine: 3, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[7]], + resultIndex: 2, + resultLine: 8, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[7]], + resultIndex: 0, + resultLine: 1, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep(true)); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[7]], + resultIndex: 2, + resultLine: 8, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.setSearchInput('FOO')); + expect(rendered.result.current).toMatchObject({ + lines: [lines[0], lines[2], lines[4], lines[5]], + searchInput: 'FOO', + searchText: 'foo', + shouldFilter: true, + resultCount: 7, + resultIndex: 2, + resultLine: 3, + resultLineIndex: 1, + }); + + act(() => rendered.result.current.toggleShouldFilter()); + expect(rendered.result.current).toMatchObject({ + lines, + shouldFilter: false, + resultCount: 7, + resultIndex: 2, + resultLine: 3, + resultLineIndex: 1, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + lines, + searchInput: 'FOO', + searchText: 'foo', + shouldFilter: false, + resultCount: 7, + resultIndex: 3, + resultLine: 5, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + resultIndex: 4, + resultLine: 6, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + resultIndex: 5, + resultLine: 6, + resultLineIndex: 1, + }); + + act(() => rendered.result.current.resultIndexStep()); + expect(rendered.result.current).toMatchObject({ + resultIndex: 6, + resultLine: 6, + resultLineIndex: 2, + }); + + act(() => rendered.result.current.setSearchInput('BAR')); + expect(rendered.result.current).toMatchObject({ + searchText: 'bar', + resultCount: 3, + resultIndex: 6, + resultLine: 8, + resultLineIndex: 0, + }); + + act(() => rendered.result.current.resultIndexStep(true)); + expect(rendered.result.current).toMatchObject({ + searchText: 'bar', + resultCount: 3, + resultIndex: 1, + resultLine: 3, + resultLineIndex: 0, + }); + }); +}); diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx new file mode 100644 index 0000000000..4462a3ff50 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx @@ -0,0 +1,117 @@ +/* + * 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 { useMemo, useState } from 'react'; +import { useToggle } from 'react-use'; +import { AnsiLine } from './AnsiProcessor'; + +export function applySearchFilter(lines: AnsiLine[], searchText: string) { + if (!searchText) { + return { lines }; + } + + const matchingLines = []; + const searchResults = []; + for (const line of lines) { + if (line.text.includes(searchText)) { + matchingLines.push(line); + + let offset = 0; + let lineResultIndex = 0; + for (;;) { + const start = line.text.indexOf(searchText, offset); + if (start === -1) { + break; + } + searchResults.push({ + lineNumber: line.lineNumber, + lineIndex: lineResultIndex++, + }); + offset = start + searchText.length; + } + } + } + + return { + lines: matchingLines, + results: searchResults, + }; +} + +export interface LogViewerSearch { + lines: AnsiLine[]; + + searchText: string; + searchInput: string; + setSearchInput: (searchInput: string) => void; + + shouldFilter: boolean; + toggleShouldFilter: () => void; + + resultCount: number | undefined; + resultIndex: number | undefined; + resultIndexStep: (decrement?: boolean) => void; + + resultLine: number | undefined; + resultLineIndex: number | undefined; +} + +export function useLogViewerSearch(lines: AnsiLine[]): LogViewerSearch { + const [searchInput, setSearchInput] = useState(''); + const searchText = searchInput.toLocaleLowerCase('en-US'); + + const [resultIndex, setResultIndex] = useState(0); + + const [shouldFilter, toggleShouldFilter] = useToggle(false); + + const filter = useMemo( + () => applySearchFilter(lines, searchText), + [lines, searchText], + ); + + const searchResult = filter.results + ? filter.results[Math.min(resultIndex, filter.results.length - 1)] + : undefined; + const resultCount = filter.results?.length; + + const resultIndexStep = (decrement?: boolean) => { + if (decrement) { + if (resultCount !== undefined) { + const next = Math.min(resultIndex - 1, resultCount - 2); + setResultIndex(next < 0 ? resultCount - 1 : next); + } + } else { + if (resultCount !== undefined) { + const next = resultIndex + 1; + setResultIndex(next >= resultCount ? 0 : next); + } + } + }; + + return { + lines: shouldFilter ? filter.lines : lines, + searchText, + searchInput, + setSearchInput, + shouldFilter, + toggleShouldFilter, + resultCount, + resultIndex, + resultIndexStep, + resultLine: searchResult?.lineNumber, + resultLineIndex: searchResult?.lineIndex, + }; +} diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx new file mode 100644 index 0000000000..7e00d50f33 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx @@ -0,0 +1,123 @@ +/* + * 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 React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { TestApiProvider, MockErrorApi } from '@backstage/test-utils'; +import { errorApiRef } from '@backstage/core-plugin-api'; +import { AnsiLine } from './AnsiProcessor'; +import { useLogViewerSelection } from './useLogViewerSelection'; +// eslint-disable-next-line import/no-extraneous-dependencies +import copyToClipboard from 'copy-to-clipboard'; + +// Used by useCopyToClipboard +jest.mock('copy-to-clipboard', () => ({ + __esModule: true, + default: jest.fn(), +})); + +const lines = [ + new AnsiLine(1, [{ text: '1', modifiers: {} }]), + new AnsiLine(2, [{ text: '2', modifiers: {} }]), + new AnsiLine(3, [{ text: '3', modifiers: {} }]), + new AnsiLine(4, [{ text: '4', modifiers: {} }]), + new AnsiLine(5, [{ text: '5', modifiers: {} }]), +]; + +describe('useLogViewerSelection', () => { + it('should manage a selection', () => { + const rendered = renderHook(() => useLogViewerSelection(lines), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(rendered.result.current.isSelected(1)).toBe(false); + expect(rendered.result.current.isSelected(2)).toBe(false); + expect(rendered.result.current.isSelected(3)).toBe(false); + + expect(rendered.result.current.shouldShowButton(1)).toBe(false); + expect(rendered.result.current.shouldShowButton(2)).toBe(false); + expect(rendered.result.current.shouldShowButton(3)).toBe(false); + + act(() => rendered.result.current.setSelection(2, false)); + + expect(rendered.result.current.isSelected(1)).toBe(false); + expect(rendered.result.current.isSelected(2)).toBe(true); + expect(rendered.result.current.isSelected(3)).toBe(false); + + expect(rendered.result.current.shouldShowButton(1)).toBe(false); + expect(rendered.result.current.shouldShowButton(2)).toBe(true); + expect(rendered.result.current.shouldShowButton(3)).toBe(false); + + act(() => rendered.result.current.setSelection(3, false)); + + expect(rendered.result.current.isSelected(1)).toBe(false); + expect(rendered.result.current.isSelected(2)).toBe(false); + expect(rendered.result.current.isSelected(3)).toBe(true); + expect(rendered.result.current.isSelected(4)).toBe(false); + + expect(rendered.result.current.shouldShowButton(1)).toBe(false); + expect(rendered.result.current.shouldShowButton(2)).toBe(false); + expect(rendered.result.current.shouldShowButton(3)).toBe(true); + expect(rendered.result.current.shouldShowButton(4)).toBe(false); + + act(() => rendered.result.current.setSelection(1, true)); + + expect(rendered.result.current.isSelected(1)).toBe(true); + expect(rendered.result.current.isSelected(2)).toBe(true); + expect(rendered.result.current.isSelected(3)).toBe(true); + expect(rendered.result.current.isSelected(4)).toBe(false); + + expect(rendered.result.current.shouldShowButton(1)).toBe(true); + expect(rendered.result.current.shouldShowButton(2)).toBe(false); + expect(rendered.result.current.shouldShowButton(3)).toBe(true); + expect(rendered.result.current.shouldShowButton(4)).toBe(false); + + act(() => rendered.result.current.setSelection(4, true)); + + expect(rendered.result.current.isSelected(1)).toBe(false); + expect(rendered.result.current.isSelected(2)).toBe(false); + expect(rendered.result.current.isSelected(3)).toBe(true); + expect(rendered.result.current.isSelected(4)).toBe(true); + expect(rendered.result.current.isSelected(5)).toBe(false); + + expect(rendered.result.current.shouldShowButton(1)).toBe(false); + expect(rendered.result.current.shouldShowButton(2)).toBe(false); + expect(rendered.result.current.shouldShowButton(3)).toBe(true); + expect(rendered.result.current.shouldShowButton(4)).toBe(true); + expect(rendered.result.current.shouldShowButton(5)).toBe(false); + + expect(copyToClipboard).not.toHaveBeenCalled(); + act(() => rendered.result.current.copySelection()); + expect(copyToClipboard).toHaveBeenLastCalledWith('3\n4'); + + act(() => rendered.result.current.setSelection(2, true)); + act(() => rendered.result.current.setSelection(4, true)); + + act(() => rendered.result.current.copySelection()); + expect(copyToClipboard).toHaveBeenCalledWith('2\n3\n4'); + + act(() => rendered.result.current.setSelection(2, false)); + act(() => rendered.result.current.setSelection(4, false)); + act(() => rendered.result.current.setSelection(4, false)); + act(() => rendered.result.current.setSelection(5, true)); + act(() => rendered.result.current.copySelection()); + expect(copyToClipboard).toHaveBeenCalledWith('5'); + }); +}); diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSelection.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSelection.tsx new file mode 100644 index 0000000000..a41f5e7159 --- /dev/null +++ b/packages/core-components/src/components/LogViewer/useLogViewerSelection.tsx @@ -0,0 +1,70 @@ +/* + * 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 { errorApiRef, useApi } from '@backstage/core-plugin-api'; +import { useEffect, useState } from 'react'; +import { useCopyToClipboard } from 'react-use'; +import { AnsiLine } from './AnsiProcessor'; + +export function useLogViewerSelection(lines: AnsiLine[]) { + const errorApi = useApi(errorApiRef); + const [sel, setSelection] = useState<{ start: number; end: number }>(); + const start = sel ? Math.min(sel.start, sel.end) : undefined; + const end = sel ? Math.max(sel.start, sel.end) : undefined; + + const [{ error }, copyToClipboard] = useCopyToClipboard(); + + useEffect(() => { + if (error) { + errorApi.post(error); + } + }, [error, errorApi]); + + return { + shouldShowButton(line: number) { + return start === line || end === line; + }, + isSelected(line: number) { + if (!sel) { + return false; + } + return start! <= line && line <= end!; + }, + setSelection(line: number, add: boolean) { + if (add) { + setSelection(s => + s ? { start: s.start, end: line } : { start: line, end: line }, + ); + } else { + setSelection(s => + s?.start === line && s?.end === line + ? undefined + : { start: line, end: line }, + ); + } + }, + copySelection() { + if (sel) { + const copyText = lines + .slice(Math.min(sel.start, sel.end) - 1, Math.max(sel.start, sel.end)) + .map(l => l.chunks.map(c => c.text).join('')) + .join('\n'); + copyToClipboard(copyText); + setSelection(undefined); + } + }, + }; +} diff --git a/packages/core-components/src/components/Progress/Progress.test.tsx b/packages/core-components/src/components/Progress/Progress.test.tsx index 4f4e74ce08..d4057c1675 100644 --- a/packages/core-components/src/components/Progress/Progress.test.tsx +++ b/packages/core-components/src/components/Progress/Progress.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { renderInTestApp } from '@backstage/test-utils'; -import { act } from 'react-dom/test-utils'; +import { act } from '@testing-library/react'; import { Progress } from './Progress'; diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx index bbd48c127c..f76524fe50 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx @@ -14,9 +14,8 @@ * limitations under the License. */ import { renderInTestApp } from '@backstage/test-utils'; -import { fireEvent } from '@testing-library/react'; +import { act, fireEvent } from '@testing-library/react'; import React from 'react'; -import { act } from 'react-dom/test-utils'; import { Route, Routes } from 'react-router'; import { RoutedTabs } from './RoutedTabs'; diff --git a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx index 2bc60783d7..55422faffc 100644 --- a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -14,9 +14,8 @@ * limitations under the License. */ import { renderInTestApp, withLogCollector } from '@backstage/test-utils'; -import { fireEvent } from '@testing-library/react'; +import { act, fireEvent } from '@testing-library/react'; import React from 'react'; -import { act } from 'react-dom/test-utils'; import { Route, Routes } from 'react-router'; import { TabbedLayout } from './TabbedLayout'; diff --git a/packages/core-components/src/components/index.ts b/packages/core-components/src/components/index.ts index 3c9376a894..473fab8444 100644 --- a/packages/core-components/src/components/index.ts +++ b/packages/core-components/src/components/index.ts @@ -30,6 +30,7 @@ export * from './HeaderIconLinkRow'; export * from './HorizontalScrollGrid'; export * from './Lifecycle'; export * from './Link'; +export * from './LogViewer'; export * from './MarkdownContent'; export * from './OAuthRequestDialog'; export * from './OverflowTooltip'; diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 647495a6f1..a1572402bb 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -16,7 +16,7 @@ import { makeStyles } from '@material-ui/core/styles'; import useMediaQuery from '@material-ui/core/useMediaQuery'; -import clsx from 'clsx'; +import classnames from 'classnames'; import React, { useState, useContext, PropsWithChildren, useRef } from 'react'; import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; @@ -163,7 +163,7 @@ const DesktopSidebar = ({ onMouseLeave={handleClose} onBlur={handleClose} data-testid="sidebar-root" - className={clsx(classes.drawer, { + className={classnames(classes.drawer, { [classes.drawerOpen]: isOpen, })} > diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index d7bea9876d..64c9f3aefe 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -24,7 +24,7 @@ import Typography from '@material-ui/core/Typography'; import { CreateCSSProperties } from '@material-ui/core/styles/withStyles'; import ArrowRightIcon from '@material-ui/icons/ArrowRight'; import SearchIcon from '@material-ui/icons/Search'; -import clsx from 'clsx'; +import classnames from 'classnames'; import React, { Children, forwardRef, @@ -343,10 +343,11 @@ const SidebarItemWithSubmenu = ({ onMouseLeave={handleMouseLeave} onTouchStart={isHoveredOn ? handleMouseLeave : handleMouseEnter} onMouseEnter={handleMouseEnter} + className={classnames(isHoveredOn && classes.highlighted)} >
); }); @@ -474,7 +478,7 @@ export const SidebarItem = forwardRef((props, ref) => { variant="dot" overlap="circular" invisible={!hasNotifications} - className={clsx({ [classes.closedItemIcon]: !isOpen })} + className={classnames({ [classes.closedItemIcon]: !isOpen })} > @@ -500,7 +504,7 @@ export const SidebarItem = forwardRef((props, ref) => { const childProps = { onClick, - className: clsx( + className: classnames( className, classes.root, isOpen ? classes.open : classes.closed, diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index dfa895df71..d5adbb31d8 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -15,8 +15,8 @@ */ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; -import clsx from 'clsx'; -import React, { PropsWithChildren, ReactNode, useContext } from 'react'; +import classnames from 'classnames'; +import React, { ReactNode, useContext } from 'react'; import { SidebarItemWithSubmenuContext, sidebarConfig, @@ -97,28 +97,24 @@ export type SidebarSubmenuProps = { * * @public */ -export const SidebarSubmenu = ({ - title, - children, -}: PropsWithChildren) => { +export const SidebarSubmenu = (props: SidebarSubmenuProps) => { const { isOpen } = useContext(SidebarContext); const left = isOpen ? sidebarConfig.drawerWidthOpen : sidebarConfig.drawerWidthClosed; - const props = { left }; - const classes = useStyles(props)(); + const classes = useStyles({ left })(); const { isHoveredOn } = useContext(SidebarItemWithSubmenuContext); return (
- {title} + {props.title} - {children} + {props.children}
); }; diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 60dc591d92..5063e4c27a 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -24,7 +24,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import Link from '@material-ui/core/Link'; import { IconComponent } from '@backstage/core-plugin-api'; -import clsx from 'clsx'; +import classnames from 'classnames'; import { BackstageTheme } from '@backstage/theme'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp'; @@ -149,7 +149,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { @@ -56,7 +49,7 @@ const Component: ProviderComponent = ({ onResult }) => ( ); const loader: ProviderLoader = async () => { - return result; + return new GuestUserIdentity(); }; export const guestProvider: SignInProvider = { Component, loader }; diff --git a/packages/core-components/src/layout/SignInPage/index.ts b/packages/core-components/src/layout/SignInPage/index.ts index caa8506399..b3c7618f50 100644 --- a/packages/core-components/src/layout/SignInPage/index.ts +++ b/packages/core-components/src/layout/SignInPage/index.ts @@ -18,3 +18,4 @@ export type { SignInProviderConfig } from './types'; export { SignInPage } from './SignInPage'; export type { SignInPageClassKey } from './styles'; export type { CustomProviderClassKey } from './customProvider'; +export { UserIdentity } from './UserIdentity'; diff --git a/packages/core-components/src/layout/SignInPage/providers.tsx b/packages/core-components/src/layout/SignInPage/providers.tsx index 19915e6aa9..23d6c95b3c 100644 --- a/packages/core-components/src/layout/SignInPage/providers.tsx +++ b/packages/core-components/src/layout/SignInPage/providers.tsx @@ -17,10 +17,10 @@ import React, { useLayoutEffect, useState, useMemo, useCallback } from 'react'; import { SignInPageProps, - SignInResult, useApi, useApiHolder, errorApiRef, + IdentityApi, } from '@backstage/core-plugin-api'; import { IdentityProviders, @@ -30,6 +30,7 @@ import { import { commonProvider } from './commonProvider'; import { guestProvider } from './guestProvider'; import { customProvider } from './customProvider'; +import { IdentityApiSignOutProxy } from './IdentityApiSignOutProxy'; const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider'; @@ -81,7 +82,7 @@ export function getSignInProviders( export const useSignInProviders = ( providers: SignInProviderType, - onResult: SignInPageProps['onResult'], + onSignInSuccess: SignInPageProps['onSignInSuccess'], ) => { const errorApi = useApi(errorApiRef); const apiHolder = useApiHolder(); @@ -89,16 +90,18 @@ export const useSignInProviders = ( // This decorates the result with sign out logic from this hook const handleWrappedResult = useCallback( - (result: SignInResult) => { - onResult({ - ...result, - signOut: async () => { - localStorage.removeItem(PROVIDER_STORAGE_KEY); - await result.signOut?.(); - }, - }); + (identityApi: IdentityApi) => { + onSignInSuccess( + IdentityApiSignOutProxy.from({ + identityApi, + signOut: async () => { + localStorage.removeItem(PROVIDER_STORAGE_KEY); + await identityApi.signOut?.(); + }, + }), + ); }, - [onResult], + [onSignInSuccess], ); // In this effect we check if the user has already selected an existing login @@ -151,7 +154,14 @@ export const useSignInProviders = ( return () => { didCancel = true; }; - }, [loading, errorApi, onResult, apiHolder, providers, handleWrappedResult]); + }, [ + loading, + errorApi, + onSignInSuccess, + apiHolder, + providers, + handleWrappedResult, + ]); // This renders all available sign-in providers const elements = useMemo( @@ -161,7 +171,7 @@ export const useSignInProviders = ( const { Component } = provider.components; - const handleResult = (result: SignInResult) => { + const handleSignInSuccess = (result: IdentityApi) => { localStorage.setItem(PROVIDER_STORAGE_KEY, provider.id); handleWrappedResult(result); @@ -171,7 +181,7 @@ export const useSignInProviders = ( ); }), diff --git a/packages/core-components/src/layout/SignInPage/types.ts b/packages/core-components/src/layout/SignInPage/types.ts index 1e4e4a2997..5b458448bf 100644 --- a/packages/core-components/src/layout/SignInPage/types.ts +++ b/packages/core-components/src/layout/SignInPage/types.ts @@ -17,12 +17,12 @@ import { ComponentType } from 'react'; import { SignInPageProps, - SignInResult, ApiHolder, ApiRef, ProfileInfoApi, BackstageIdentityApi, SessionApi, + IdentityApi, } from '@backstage/core-plugin-api'; export type SignInProviderConfig = { @@ -41,7 +41,7 @@ export type ProviderComponent = ComponentType< export type ProviderLoader = ( apis: ApiHolder, apiRef: ApiRef, -) => Promise; +) => Promise; export type SignInProvider = { Component: ProviderComponent; diff --git a/packages/core-components/src/overridableComponents.ts b/packages/core-components/src/overridableComponents.ts index 3dc208eb70..afad472d77 100644 --- a/packages/core-components/src/overridableComponents.ts +++ b/packages/core-components/src/overridableComponents.ts @@ -34,6 +34,7 @@ import { LifecycleClassKey, MarkdownContentClassKey, LoginRequestListItemClassKey, + LogViewerClassKey, OAuthRequestDialogClassKey, OverflowTooltipClassKey, GaugeClassKey, @@ -106,6 +107,7 @@ type BackstageComponentsNameToClassKey = { BackstageLifecycle: LifecycleClassKey; BackstageMarkdownContent: MarkdownContentClassKey; BackstageLoginRequestListItem: LoginRequestListItemClassKey; + BackstageLogViewer: LogViewerClassKey; OAuthRequestDialog: OAuthRequestDialogClassKey; BackstageOverflowTooltip: OverflowTooltipClassKey; BackstageGauge: GaugeClassKey; diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index e0050f9f13..fdf64779fb 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/core-plugin-api +## 0.3.0 + +### Minor Changes + +- a036b65c2f: The `IdentityApi` has received several updates. The `getUserId`, `getProfile`, and `getIdToken` have all been deprecated. + + The replacement for `getUserId` is the new `getBackstageIdentity` method, which provides both the `userEntityRef` as well as the `ownershipEntityRefs` that are used to resolve ownership. Existing usage of the user ID would typically be using a fixed entity kind and namespace, for example `` `user:default/${identityApi.getUserId()}` ``, this kind of usage should now instead use the `userEntityRef` directly. + + The replacement for `getProfile` is the new async `getProfileInfo`. + + The replacement for `getIdToken` is the new `getCredentials` method, which provides an optional token to the caller like before, but it is now wrapped in an object for forwards compatibility. + + The deprecated `idToken` field of the `BackstageIdentity` type has been removed, leaving only the new `token` field, which should be used instead. The `BackstageIdentity` also received a new `identity` field, which is a decoded version of the information within the token. Furthermore the `BackstageIdentity` has been renamed to `BackstageIdentityResponse`, with the old name being deprecated. + + We expect most of the breaking changes in this update to have low impact since the `IdentityApi` implementation is provided by the app, but it is likely that some tests need to be updated. + + Another breaking change is that the `SignInPage` props have been updated, and the `SignInResult` type is now deprecated. This is unlikely to have any impact on the usage of this package, but it is an important change that you can find more information about in the [`@backstage/core-app-api` CHANGELOG.md](https://github.com/backstage/backstage/blob/master/packages/core-app-api/CHANGELOG.md). + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/version-bridge@0.1.1 + ## 0.2.2 ### Patch Changes diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 560071e1fa..d0ac0b5352 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -10,6 +10,7 @@ import { BackstageTheme } from '@backstage/theme'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; import { IconComponent as IconComponent_2 } from '@backstage/core-plugin-api'; +import { IdentityApi as IdentityApi_2 } from '@backstage/core-plugin-api'; import { Observable as Observable_2 } from '@backstage/types'; import { Observer as Observer_2 } from '@backstage/types'; import { ProfileInfo as ProfileInfo_2 } from '@backstage/core-plugin-api'; @@ -43,10 +44,7 @@ export type AnalyticsApi = { export const analyticsApiRef: ApiRef; // @public -export const AnalyticsContext: ({ - attributes, - children, -}: { +export const AnalyticsContext: (options: { attributes: Partial; children: ReactNode; }) => JSX.Element; @@ -236,18 +234,21 @@ export type AuthRequestOptions = { instantPopup?: boolean; }; -// @public -export type BackstageIdentity = { - id: string; - idToken: string; - token: string; -}; +// @public @deprecated +export type BackstageIdentity = BackstageIdentityResponse; // @public export type BackstageIdentityApi = { getBackstageIdentity( options?: AuthRequestOptions, - ): Promise; + ): Promise; +}; + +// @public +export type BackstageIdentityResponse = { + id: string; + token: string; + identity: BackstageUserIdentity; }; // @public @@ -264,6 +265,13 @@ export type BackstagePlugin< externalRoutes: ExternalRoutes; }; +// @public +export type BackstageUserIdentity = { + type: 'user'; + userEntityRef: string; + ownershipEntityRefs: string[]; +}; + // @public export const bitbucketAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -531,8 +539,13 @@ export type IconComponent = ComponentType<{ // @public export type IdentityApi = { getUserId(): string; - getProfile(): ProfileInfo; getIdToken(): Promise; + getProfile(): ProfileInfo; + getProfileInfo(): Promise; + getBackstageIdentity(): Promise; + getCredentials(): Promise<{ + token?: string; + }>; signOut(): Promise; }; @@ -745,10 +758,10 @@ export enum SessionState { // @public export type SignInPageProps = { - onResult(result: SignInResult): void; + onSignInSuccess(identityApi: IdentityApi_2): void; }; -// @public +// @public @deprecated export type SignInResult = { userId: string; profile: ProfileInfo_2; diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 3e07207c9d..72827bde73 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "0.2.2", + "version": "0.3.0", "private": false, "publishConfig": { "access": "public", @@ -32,20 +32,22 @@ "@backstage/config": "^0.1.11", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", - "@backstage/version-bridge": "^0.1.0", + "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", - "@types/react": "*", "history": "^5.0.0", "prop-types": "^15.7.2", - "react": "^16.12.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx b/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx index bb2141d47f..075cdff3ff 100644 --- a/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx +++ b/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx @@ -62,13 +62,12 @@ export const useAnalyticsContext = (): AnalyticsContextValue => { * * @public */ -export const AnalyticsContext = ({ - attributes, - children, -}: { +export const AnalyticsContext = (options: { attributes: Partial; children: ReactNode; }) => { + const { attributes, children } = options; + const parentValues = useAnalyticsContext(); const combinedValue = { ...parentValues, diff --git a/packages/core-plugin-api/src/apis/definitions/IdentityApi.ts b/packages/core-plugin-api/src/apis/definitions/IdentityApi.ts index 9f68a8b2cc..fe4de89106 100644 --- a/packages/core-plugin-api/src/apis/definitions/IdentityApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/IdentityApi.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { ApiRef, createApiRef } from '../system'; -import { ProfileInfo } from './auth'; +import { BackstageUserIdentity, ProfileInfo } from './auth'; /** * The Identity API used to identify and get information about the signed in user. @@ -26,25 +26,45 @@ export type IdentityApi = { * The ID of the signed in user. This ID is not meant to be presented to the user, but used * as an opaque string to pass on to backends or use in frontend logic. * - * TODO: The intention of the user ID is to be able to tie the user to an identity - * that is known by the catalog and/or identity backend. It should for example - * be possible to fetch all owned components using this ID. + * @deprecated use {@link IdentityApi.getBackstageIdentity} instead. */ getUserId(): string; - /** - * The profile of the signed in user. - */ - getProfile(): ProfileInfo; - /** * An OpenID Connect ID Token which proves the identity of the signed in user. * * The ID token will be undefined if the signed in user does not have a verified * identity, such as a demo user or mocked user for e2e tests. + * + * @deprecated use {@link IdentityApi.getCredentials} instead. */ getIdToken(): Promise; + /** + * The profile of the signed in user. + * + * @deprecated use {@link IdentityApi.getProfileInfo} instead. + */ + getProfile(): ProfileInfo; + + /** + * The profile of the signed in user. + */ + getProfileInfo(): Promise; + + /** + * User identity information within Backstage. + */ + getBackstageIdentity(): Promise; + + /** + * Provides credentials in the form of a token which proves the identity of the signed in user. + * + * The token will be undefined if the signed in user does not have a verified + * identity, such as a demo user or mocked user for e2e tests. + */ + getCredentials(): Promise<{ token?: string }>; + /** * Sign out the current user */ diff --git a/packages/core-plugin-api/src/apis/definitions/auth.ts b/packages/core-plugin-api/src/apis/definitions/auth.ts index 8fe532f3a6..37308ec29b 100644 --- a/packages/core-plugin-api/src/apis/definitions/auth.ts +++ b/packages/core-plugin-api/src/apis/definitions/auth.ts @@ -160,31 +160,65 @@ export type BackstageIdentityApi = { */ getBackstageIdentity( options?: AuthRequestOptions, - ): Promise; + ): Promise; }; /** - * A (user id, token) pair. + * User identity information within Backstage. * * @public */ -export type BackstageIdentity = { +export type BackstageUserIdentity = { /** - * The backstage user ID. + * The type of identity that this structure represents. In the frontend app + * this will currently always be 'user'. */ - id: string; + type: 'user'; /** - * @deprecated This is deprecated, use `token` instead. + * The entityRef of the user in the catalog. + * For example User:default/sandra */ - idToken: string; + userEntityRef: string; + + /** + * The user and group entities that the user claims ownership through + */ + ownershipEntityRefs: string[]; +}; + +/** + * Token and Identity response, with the users claims in the Identity. + * + * @public + */ +export type BackstageIdentityResponse = { + /** + * The backstage user ID. + * + * @deprecated The identity is now provided via the `identity` field instead. + */ + id: string; /** * The token used to authenticate the user within Backstage. */ token: string; + + /** + * Identity information derived from the token. + */ + identity: BackstageUserIdentity; }; +/** + * The old exported symbol for {@link BackstageIdentityResponse}. + * + * @public + * @deprecated use {@link BackstageIdentityResponse} instead. + */ +export type BackstageIdentity = BackstageIdentityResponse; + /** * Profile information of the user. * diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 599fdf78f3..cdcf7f4952 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/create-app +## 0.4.7 + +### Patch Changes + +- 9603827bb5: Addressed some peer dependency warnings +- 1bada775a9: TechDocs Backend may now (optionally) leverage a cache store to improve + performance when reading content from a cloud storage provider. + + To apply this change to an existing app, pass the cache manager from the plugin + environment to the `createRouter` function in your backend: + + ```diff + // packages/backend/src/plugins/techdocs.ts + + export default async function createPlugin({ + logger, + config, + discovery, + reader, + + cache, + }: PluginEnvironment): Promise { + + // ... + + return await createRouter({ + preparers, + generators, + publisher, + logger, + config, + discovery, + + cache, + }); + ``` + + If your `PluginEnvironment` does not include a cache manager, be sure you've + applied [the cache management change][cm-change] to your backend as well. + + [Additional configuration][td-rec-arch] is required if you wish to enable + caching in TechDocs. + + [cm-change]: https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md#patch-changes-6 + [td-rec-arch]: https://backstage.io/docs/features/techdocs/architecture#recommended-deployment + +- 4862fbc64f: Bump @spotify/prettier-config +- 36bb4fb2e9: Removed the `scaffolder.github.visibility` configuration that is no longer used from the default app template. + ## 0.4.6 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index b2fa1a1acf..ec739820b9 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.6", + "version": "0.4.7", "private": false, "publishConfig": { "access": "public" diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index b882155a3d..e15249bf91 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/dev-utils +## 0.2.14 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/core-app-api@0.2.0 + - @backstage/app-defaults@0.1.2 + - @backstage/integration-react@0.1.15 + - @backstage/test-utils@0.1.24 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.13 ### Patch Changes diff --git a/packages/dev-utils/api-report.md b/packages/dev-utils/api-report.md index c10de7d529..e1cb93313f 100644 --- a/packages/dev-utils/api-report.md +++ b/packages/dev-utils/api-report.md @@ -44,11 +44,9 @@ export type DevAppPageOptions = { }; // @public (undocumented) -export const EntityGridItem: ({ - entity, - classes, - ...rest -}: Omit, 'container' | 'item'> & { - entity: Entity; -}) => JSX.Element; +export const EntityGridItem: ( + props: Omit & { + entity: Entity; + }, +) => JSX.Element; ``` diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 110d774777..8f77f4a72d 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.2.13", + "version": "0.2.14", "private": false, "publishConfig": { "access": "public", @@ -29,31 +29,33 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/app-defaults": "^0.1.1", - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/app-defaults": "^0.1.2", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/catalog-model": "^0.9.7", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog-react": "^0.6.4", - "@backstage/test-utils": "^0.1.22", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/test-utils": "^0.1.24", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", - "@types/react": "*", - "react": "^16.12.0", "react-use": "^17.2.4", - "react-dom": "^16.12.0", "react-hot-loader": "^4.12.21", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx b/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx index 55327f35e5..a66550a4d2 100644 --- a/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx +++ b/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx @@ -35,11 +35,10 @@ const useStyles = makeStyles(theme => ({ })); /** @public */ -export const EntityGridItem = ({ - entity, - classes, - ...rest -}: Omit & { entity: Entity }): JSX.Element => { +export const EntityGridItem = ( + props: Omit & { entity: Entity }, +): JSX.Element => { + const { entity, classes, ...rest } = props; const itemClasses = useStyles({ entity }); return ( diff --git a/packages/embedded-techdocs-app/CHANGELOG.md b/packages/embedded-techdocs-app/CHANGELOG.md index 13aa9aabe3..f1ae8abdf5 100644 --- a/packages/embedded-techdocs-app/CHANGELOG.md +++ b/packages/embedded-techdocs-app/CHANGELOG.md @@ -1,5 +1,20 @@ # embedded-techdocs-app +## 0.2.56 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog@0.7.4 + - @backstage/core-app-api@0.2.0 + - @backstage/app-defaults@0.1.2 + - @backstage/integration-react@0.1.15 + - @backstage/test-utils@0.1.24 + - @backstage/plugin-techdocs@0.12.9 + - @backstage/cli@0.10.1 + ## 0.2.55 ### Patch Changes diff --git a/packages/embedded-techdocs-app/package.json b/packages/embedded-techdocs-app/package.json index 24db320eaa..6a13acf37f 100644 --- a/packages/embedded-techdocs-app/package.json +++ b/packages/embedded-techdocs-app/package.json @@ -1,20 +1,20 @@ { "name": "embedded-techdocs-app", - "version": "0.2.55", + "version": "0.2.56", "private": true, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^0.1.1", + "@backstage/app-defaults": "^0.1.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@backstage/config": "^0.1.10", - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog": "^0.7.3", - "@backstage/plugin-techdocs": "^0.12.8", - "@backstage/test-utils": "^0.1.22", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/plugin-techdocs": "^0.12.9", + "@backstage/test-utils": "^0.1.24", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -26,7 +26,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index e972b4d4e8..b56d4f52d1 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 0.1.15 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.1.14 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index be38d92b64..988fd14032 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "0.1.14", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,21 +22,22 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/integration": "^0.6.10", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.22", + "@backstage/cli": "^0.10.1", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/packages/storybook/package.json b/packages/storybook/package.json index 736afbb8d8..5df0c06632 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "@backstage/theme": "^0.2.0", - "react": "^16.12.0", - "react-dom": "^16.12.0" + "react": "^16.13.1", + "react-dom": "^16.13.1" }, "devDependencies": { "@storybook/addon-a11y": "^6.3.4", diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index d07361e915..cf94063b89 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,13 @@ # @techdocs/cli +## 0.8.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.9.13 + - @backstage/techdocs-common@0.11.0 + ## 0.8.7 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 34d67d4dc9..292db9820f 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "0.8.7", + "version": "0.8.8", "private": false, "publishConfig": { "access": "public" @@ -32,7 +32,7 @@ "techdocs-cli": "bin/techdocs-cli" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", @@ -41,7 +41,7 @@ "@types/react-dev-utils": "^9.0.4", "@types/serve-handler": "^6.1.0", "@types/webpack-env": "^1.15.3", - "embedded-techdocs-app": "0.2.55", + "embedded-techdocs-app": "0.2.56", "find-process": "^1.4.5", "nodemon": "^2.0.2", "ts-node": "^10.0.0" @@ -56,10 +56,10 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", - "@backstage/techdocs-common": "^0.10.7", + "@backstage/techdocs-common": "^0.11.0", "@types/dockerode": "^3.3.0", "commander": "^6.1.0", "dockerode": "^3.3.1", diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md index 386c584196..e925ad35e9 100644 --- a/packages/techdocs-common/CHANGELOG.md +++ b/packages/techdocs-common/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/techdocs-common +## 0.11.0 + +### Minor Changes + +- 1bada775a9: Added the ability for the TechDocs Backend to (optionally) leverage a cache + store to improve performance when reading files from a cloud storage provider. + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.10.8 ### Patch Changes diff --git a/packages/techdocs-common/api-report.md b/packages/techdocs-common/api-report.md index b2f9e40d0a..5c0a9f87f6 100644 --- a/packages/techdocs-common/api-report.md +++ b/packages/techdocs-common/api-report.md @@ -49,22 +49,6 @@ export type GeneratorBuilder = { get(entity: Entity): GeneratorBase; }; -// 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-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-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-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-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-missing-release-tag) "GeneratorRunOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export type GeneratorRunOptions = { inputDir: string; @@ -82,10 +66,7 @@ export class Generators implements GeneratorBuilder { // (undocumented) static fromConfig( config: Config, - { - logger, - containerRunner, - }: { + options: { logger: Logger_2; containerRunner: ContainerRunner; }, @@ -185,13 +166,10 @@ export class Publisher { ): Promise; } -// Warning: (ae-missing-release-tag) "PublisherBase" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export interface PublisherBase { docsRouter(): express.Handler; fetchTechDocsMetadata(entityName: EntityName): Promise; - // Warning: (ae-forgotten-export) The symbol "ReadinessResponse" needs to be exported by the entry point index.d.ts getReadiness(): Promise; hasDocsBeenGenerated(entityName: Entity): Promise; // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -202,7 +180,6 @@ export interface PublisherBase { // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" // Warning: (ae-forgotten-export) The symbol "MigrateRequest" needs to be exported by the entry point index.d.ts migrateDocsCase?(migrateRequest: MigrateRequest): Promise; - // 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 "PublishRequest" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "PublishResponse" needs to be exported by the entry point index.d.ts publish(request: PublishRequest): Promise; @@ -218,6 +195,11 @@ export type PublisherType = | 'azureBlobStorage' | 'openStackSwift'; +// @public +export type ReadinessResponse = { + isAvailable: boolean; +}; + // Warning: (ae-missing-release-tag) "RemoteProtocol" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -245,12 +227,7 @@ export interface TechDocsDocument extends IndexableDocument { // // @public (undocumented) export class TechdocsGenerator implements GeneratorBase { - constructor({ - logger, - containerRunner, - config, - scmIntegrations, - }: { + constructor(options: { logger: Logger_2; containerRunner: ContainerRunner; config: Config; @@ -260,26 +237,15 @@ export class TechdocsGenerator implements GeneratorBase { // (undocumented) static fromConfig( config: Config, - { - containerRunner, - logger, - }: { + options: { containerRunner: ContainerRunner; logger: Logger_2; }, ): TechdocsGenerator; // (undocumented) - run({ - inputDir, - outputDir, - parsedLocationAnnotation, - etag, - logger: childLogger, - logStream, - }: GeneratorRunOptions): Promise; + run(options: GeneratorRunOptions): 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) "TechDocsMetadata" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -319,7 +285,7 @@ export class UrlPreparer implements PreparerBase { // Warnings were encountered during analysis: // -// src/stages/generate/types.d.ts:44:5 - (ae-forgotten-export) The symbol "SupportedGeneratorKey" needs to be exported by the entry point index.d.ts +// src/stages/generate/types.d.ts:45:5 - (ae-forgotten-export) The symbol "SupportedGeneratorKey" needs to be exported by the entry point index.d.ts // src/stages/prepare/types.d.ts:18:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // src/stages/prepare/types.d.ts:19:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters // src/stages/prepare/types.d.ts:21:33 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index e6956b87e6..c9c67881f7 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/techdocs-common", "description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "0.10.8", + "version": "0.11.0", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -38,7 +38,7 @@ "dependencies": { "@azure/identity": "^1.5.0", "@azure/storage-blob": "^12.5.0", - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", @@ -60,7 +60,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/fs-extra": "^9.0.5", "@types/js-yaml": "^4.0.0", "@types/mime-types": "^2.1.0", diff --git a/packages/techdocs-common/src/stages/generate/generators.ts b/packages/techdocs-common/src/stages/generate/generators.ts index 3d1ad2b73b..de39d4e7c3 100644 --- a/packages/techdocs-common/src/stages/generate/generators.ts +++ b/packages/techdocs-common/src/stages/generate/generators.ts @@ -31,17 +31,11 @@ export class Generators implements GeneratorBuilder { static async fromConfig( config: Config, - { - logger, - containerRunner, - }: { logger: Logger; containerRunner: ContainerRunner }, + options: { logger: Logger; containerRunner: ContainerRunner }, ): Promise { const generators = new Generators(); - const techdocsGenerator = TechdocsGenerator.fromConfig(config, { - logger, - containerRunner, - }); + const techdocsGenerator = TechdocsGenerator.fromConfig(config, options); generators.register('techdocs', techdocsGenerator); return generators; diff --git a/packages/techdocs-common/src/stages/generate/techdocs.ts b/packages/techdocs-common/src/stages/generate/techdocs.ts index 8681736815..a6eb8d38d2 100644 --- a/packages/techdocs-common/src/stages/generate/techdocs.ts +++ b/packages/techdocs-common/src/stages/generate/techdocs.ts @@ -52,11 +52,9 @@ export class TechdocsGenerator implements GeneratorBase { static fromConfig( config: Config, - { - containerRunner, - logger, - }: { containerRunner: ContainerRunner; logger: Logger }, + options: { containerRunner: ContainerRunner; logger: Logger }, ) { + const { containerRunner, logger } = options; const scmIntegrations = ScmIntegrations.fromConfig(config); return new TechdocsGenerator({ logger, @@ -66,31 +64,28 @@ export class TechdocsGenerator implements GeneratorBase { }); } - constructor({ - logger, - containerRunner, - config, - scmIntegrations, - }: { + constructor(options: { logger: Logger; containerRunner: ContainerRunner; config: Config; scmIntegrations: ScmIntegrationRegistry; }) { - this.logger = logger; - this.options = readGeneratorConfig(config, logger); - this.containerRunner = containerRunner; - this.scmIntegrations = scmIntegrations; + this.logger = options.logger; + this.options = readGeneratorConfig(options.config, options.logger); + this.containerRunner = options.containerRunner; + this.scmIntegrations = options.scmIntegrations; } - public async run({ - inputDir, - outputDir, - parsedLocationAnnotation, - etag, - logger: childLogger, - logStream, - }: GeneratorRunOptions): Promise { + public async run(options: GeneratorRunOptions): Promise { + const { + inputDir, + outputDir, + parsedLocationAnnotation, + etag, + logger: childLogger, + logStream, + } = options; + // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url const { path: mkdocsYmlPath, content } = await getMkdocsYml(inputDir); diff --git a/packages/techdocs-common/src/stages/generate/types.ts b/packages/techdocs-common/src/stages/generate/types.ts index 3559716be0..2a090d5584 100644 --- a/packages/techdocs-common/src/stages/generate/types.ts +++ b/packages/techdocs-common/src/stages/generate/types.ts @@ -34,12 +34,13 @@ export type GeneratorConfig = { /** * The values that the generator will receive. * - * @param {string} inputDir The directory of the uncompiled documentation, with the values from the frontend - * @param {string} outputDir Directory to store generated docs in. Usually - a newly created temporary directory. - * @param {ParsedLocationAnnotation} parsedLocationAnnotation backstage.io/techdocs-ref annotation of an entity - * @param {string} etag A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json. - * @param {Logger} [logger] A logger that forwards the messages to the caller to be displayed outside of the backend. - * @param {Writable} [logStream] A log stream that can send raw log messages to the caller to be displayed outside of the backend.. + * @public + * @param inputDir - The directory of the uncompiled documentation, with the values from the frontend + * @param outputDir - Directory to store generated docs in. Usually - a newly created temporary directory. + * @param parsedLocationAnnotation - backstage.io/techdocs-ref annotation of an entity + * @param etag - A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json. + * @param logger - A logger that forwards the messages to the caller to be displayed outside of the backend. + * @param logStream - A log stream that can send raw log messages to the caller to be displayed outside of the backend. */ export type GeneratorRunOptions = { inputDir: string; diff --git a/packages/techdocs-common/src/stages/publish/index.ts b/packages/techdocs-common/src/stages/publish/index.ts index b342f33287..083cf2b8ff 100644 --- a/packages/techdocs-common/src/stages/publish/index.ts +++ b/packages/techdocs-common/src/stages/publish/index.ts @@ -14,4 +14,9 @@ * limitations under the License. */ export { Publisher } from './publish'; -export type { PublisherBase, PublisherType, TechDocsMetadata } from './types'; +export type { + PublisherBase, + PublisherType, + TechDocsMetadata, + ReadinessResponse, +} from './types'; diff --git a/packages/techdocs-common/src/stages/publish/types.ts b/packages/techdocs-common/src/stages/publish/types.ts index 1fb301340b..b7415722d6 100644 --- a/packages/techdocs-common/src/stages/publish/types.ts +++ b/packages/techdocs-common/src/stages/publish/types.ts @@ -51,6 +51,8 @@ export type PublishResponse = { /** * Result for the validation check. + * + * @public */ export type ReadinessResponse = { /** If true, the publisher is able to interact with the backing storage. */ @@ -59,7 +61,7 @@ export type ReadinessResponse = { /** * Type to hold metadata found in techdocs_metadata.json and associated with each site - * @param etag ETag of the resource used to generate the site. Usually the latest commit sha of the source repository. + * @param etag - ETag of the resource used to generate the site. Usually the latest commit sha of the source repository. */ export type TechDocsMetadata = { site_name: string; @@ -86,6 +88,8 @@ export type MigrateRequest = { * Base class for a TechDocs publisher (e.g. Local, Google GCS Bucket, AWS S3, etc.) * The publisher handles publishing of the generated static files after the prepare and generate steps of TechDocs. * It also provides APIs to communicate with the storage service. + * + * @public */ export interface PublisherBase { /** @@ -99,8 +103,8 @@ export interface PublisherBase { /** * Store the generated static files onto a storage service (either local filesystem or external service). * - * @param request Object containing the entity from the service - * catalog, and the directory that contains the generated static files from TechDocs. + * @param request - Object containing the entity from the service + * catalog, and the directory that contains the generated static files from TechDocs. */ publish(request: PublishRequest): Promise; diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index fd8ce852db..4da8ef195f 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/test-utils +## 0.1.24 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-plugin-api@0.3.0 + - @backstage/core-app-api@0.2.0 + ## 0.1.23 ### Patch Changes diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 83c209122d..a01f306fab 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -89,23 +89,13 @@ export type LogFuncs = 'log' | 'warn' | 'error'; // @public export class MockAnalyticsApi implements AnalyticsApi { // (undocumented) - captureEvent({ - action, - subject, - value, - attributes, - context, - }: AnalyticsEvent): void; + captureEvent(event: AnalyticsEvent): void; // (undocumented) getEvents(): AnalyticsEvent[]; } // @public -export function mockBreakpoint({ - matches, -}: { - matches?: boolean | undefined; -}): void; +export function mockBreakpoint(options: { matches: boolean }): void; // @public export class MockErrorApi implements ErrorApi { @@ -178,10 +168,9 @@ export function setupRequestMockHandlers(worker: { export type SyncLogCollector = () => void; // @public -export const TestApiProvider: ({ - apis, - children, -}: TestApiProviderProps) => JSX.Element; +export const TestApiProvider: ( + props: TestApiProviderProps, +) => JSX.Element; // @public export type TestApiProviderProps = { diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 87c5b346f6..a8519160df 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "0.1.23", + "version": "0.1.24", "private": false, "publishConfig": { "access": "public", @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -38,15 +38,16 @@ "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", - "@types/react": "*", - "react": "^16.12.0", - "react-dom": "^16.12.0", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/packages/test-utils/src/testUtils/TestApiProvider.tsx b/packages/test-utils/src/testUtils/TestApiProvider.tsx index b1499b0cde..6e0be81d53 100644 --- a/packages/test-utils/src/testUtils/TestApiProvider.tsx +++ b/packages/test-utils/src/testUtils/TestApiProvider.tsx @@ -120,11 +120,13 @@ export class TestApiRegistry implements ApiHolder { * * @public **/ -export const TestApiProvider = ({ - apis, - children, -}: TestApiProviderProps) => { +export const TestApiProvider = ( + props: TestApiProviderProps, +) => { return ( - + ); }; diff --git a/packages/test-utils/src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts b/packages/test-utils/src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts index 3e2fc2a01c..6da225df1c 100644 --- a/packages/test-utils/src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts +++ b/packages/test-utils/src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts @@ -19,18 +19,15 @@ import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api'; /** * Mock implementation of {@link core-plugin-api#AnalyticsApi} with helpers to ensure that events are sent correctly. * Use getEvents in tests to verify captured events. + * * @public */ export class MockAnalyticsApi implements AnalyticsApi { private events: AnalyticsEvent[] = []; - captureEvent({ - action, - subject, - value, - attributes, - context, - }: AnalyticsEvent) { + captureEvent(event: AnalyticsEvent) { + const { action, subject, value, attributes, context } = event; + this.events.push({ action, subject, diff --git a/packages/test-utils/src/testUtils/mockBreakpoint.ts b/packages/test-utils/src/testUtils/mockBreakpoint.ts index 3bc285a81d..ee759c07a5 100644 --- a/packages/test-utils/src/testUtils/mockBreakpoint.ts +++ b/packages/test-utils/src/testUtils/mockBreakpoint.ts @@ -15,8 +15,8 @@ */ /** - * This is a mocking method suggested in the Jest Doc's, as it is not implemented in JSDOM yet. - * It can be used to mock values when the MUI `useMediaQuery` hook if it is used in a tested component. + * This is a mocking method suggested in the Jest docs, as it is not implemented in JSDOM yet. + * It can be used to mock values for the MUI `useMediaQuery` hook if it is used in a tested component. * * For issues checkout the documentation: * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom @@ -26,11 +26,11 @@ * * @public */ -export default function mockBreakpoint({ matches = false }) { +export default function mockBreakpoint(options: { matches: boolean }) { Object.defineProperty(window, 'matchMedia', { writable: true, value: jest.fn().mockImplementation(query => ({ - matches: matches, + matches: options.matches ?? false, media: query, onchange: null, addListener: jest.fn(), // deprecated diff --git a/packages/test-utils/src/testUtils/testingLibrary.ts b/packages/test-utils/src/testUtils/testingLibrary.ts index 44ea20a4cc..9fb47cbc90 100644 --- a/packages/test-utils/src/testUtils/testingLibrary.ts +++ b/packages/test-utils/src/testUtils/testingLibrary.ts @@ -15,8 +15,7 @@ */ import { ReactElement } from 'react'; -import { act } from 'react-dom/test-utils'; -import { render, RenderResult } from '@testing-library/react'; +import { act, render, RenderResult } from '@testing-library/react'; /** * @public diff --git a/packages/version-bridge/CHANGELOG.md b/packages/version-bridge/CHANGELOG.md new file mode 100644 index 0000000000..e079cd6c61 --- /dev/null +++ b/packages/version-bridge/CHANGELOG.md @@ -0,0 +1,7 @@ +# @backstage/version-bridge + +## 0.1.1 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 89baaea2f5..0291cdc208 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/version-bridge", "description": "Utilities used by @backstage packages to support multiple concurrent versions", - "version": "0.1.0", + "version": "0.1.1", "private": false, "publishConfig": { "access": "public", @@ -28,12 +28,12 @@ "postpack": "backstage-cli postpack", "clean": "backstage-cli clean" }, - "dependencies": { - "@types/react": "*", - "react": "^16.12.0" + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2" diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index f769b6e133..6b8336b251 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-allure +## 0.1.8 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.7 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 5c795e919f..8b3ee3b882 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.7", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,23 +23,24 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index acc5c235f9..77a6089118 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-analytics-module-ga +## 0.1.4 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- 704235786a: Support self hosted analytics.js script via `scriptSrc` config option +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.1.3 ### Patch Changes diff --git a/plugins/analytics-module-ga/api-report.md b/plugins/analytics-module-ga/api-report.md index 7ca3b1646f..b0f3b736c3 100644 --- a/plugins/analytics-module-ga/api-report.md +++ b/plugins/analytics-module-ga/api-report.md @@ -17,13 +17,7 @@ export const analyticsModuleGA: BackstagePlugin<{}, {}>; // // @public export class GoogleAnalytics implements AnalyticsApi { - captureEvent({ - context, - action, - subject, - value, - attributes, - }: AnalyticsEvent): void; + captureEvent(event: AnalyticsEvent): void; static fromConfig(config: Config): GoogleAnalytics; } diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index e3a3c74111..15055b2a4f 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,22 +22,23 @@ }, "dependencies": { "@backstage/config": "^0.1.5", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-ga": "^3.3.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts index 23da7c8589..28202607be 100644 --- a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts +++ b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts @@ -39,19 +39,15 @@ export class GoogleAnalytics implements AnalyticsApi { /** * Instantiate the implementation and initialize ReactGA. */ - private constructor({ - cdmConfig, - trackingId, - scriptSrc, - testMode, - debug, - }: { + private constructor(options: { cdmConfig: CustomDimensionOrMetricConfig[]; trackingId: string; scriptSrc?: string; testMode: boolean; debug: boolean; }) { + const { cdmConfig, trackingId, scriptSrc, testMode, debug } = options; + this.cdmConfig = cdmConfig; // Initialize Google Analytics. @@ -102,13 +98,8 @@ export class GoogleAnalytics implements AnalyticsApi { * pageview and the rest as custom events. All custom dimensions/metrics are * applied as they should be (set on pageview, merged object on events). */ - captureEvent({ - context, - action, - subject, - value, - attributes, - }: AnalyticsEvent) { + captureEvent(event: AnalyticsEvent) { + const { context, action, subject, value, attributes } = event; const customMetadata = this.getCustomDimensionMetrics(context, attributes); if (action === 'navigate' && context.extension === 'App') { diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 74b7ae8ab9..833976fc2b 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-api-docs +## 0.6.18 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog@0.7.4 + - @backstage/plugin-catalog-react@0.6.5 + +## 0.6.17 + +### Patch Changes + +- dde1681f33: chore(dependencies): bump `graphiql` package to latest +- ef64a444ca: Update AsyncAPI component to 1.0.0-x releases + ## 0.6.16 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index e3ee7ec0aa..93df7e68aa 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.6.16", + "version": "0.6.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,31 +32,32 @@ "dependencies": { "@asyncapi/react-component": "^1.0.0-next.25", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog": "^0.7.3", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", - "graphiql": "^1.0.0-alpha.10", - "graphql": "^15.3.0", + "graphiql": "^1.5.12", + "graphql": "^16.0.0", "isomorphic-form-data": "^2.0.0", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "swagger-client": "3.16.1", "swagger-ui-react": "^4.0.0-rc.3" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index d7492ba5b4..dc45804449 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-auth-backend +## 0.5.0 + +### Minor Changes + +- a036b65c2f: **BREAKING CHANGE** The `idToken` field of `BackstageIdentity` has been removed, with the `token` taking its place. This means you may need to update existing `signIn.resolver` implementations to return an `token` rather than an `idToken`. This also applies to custom auth providers. + + The `BackstageIdentity` type has been deprecated and will be removed in the future. Taking its place is the new `BackstageSignInResult` type with the same shape. + + This change also introduces the new `BackstageIdentityResponse` that mirrors the type with the same name from `@backstage/core-plugin-api`. The `BackstageIdentityResponse` type is different from the `BackstageSignInResult` in that it also has a `identity` field which is of type `BackstageUserIdentity` and is a decoded version of the information within the token. + + When implementing a custom auth provider that is not based on the `OAuthAdapter` you may need to convert `BackstageSignInResult` into a `BackstageIdentityResponse`, this can be done using the new `prepareBackstageIdentityResponse` function. + +### Patch Changes + +- 8f461e6043: Fixes potential bug introduced in `0.4.10` which causes `OAuth2AuthProvider` to authenticate using credentials in both POST payload and headers. + This might break some stricter OAuth2 implementations so there is now a `includeBasicAuth` config option that can manually be set to `true` to enable this behavior. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/test-utils@0.1.24 + - @backstage/backend-common@0.9.13 + ## 0.4.10 ### Patch Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 46d8b03cbb..a637118130 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -103,7 +103,7 @@ export interface AuthProviderRouteHandlers { export type AuthResponse = { providerInfo: ProviderInfo; profile: ProfileInfo; - backstageIdentity?: BackstageIdentity; + backstageIdentity?: BackstageIdentityResponse; }; // Warning: (ae-missing-release-tag) "AwsAlbProviderOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -116,14 +116,28 @@ export type AwsAlbProviderOptions = { }; }; -// Warning: (ae-missing-release-tag) "BackstageIdentity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type BackstageIdentity = { - id: string; - idToken?: string; - token?: string; +// @public @deprecated +export type BackstageIdentity = BackstageSignInResult; + +// @public +export interface BackstageIdentityResponse extends BackstageSignInResult { + identity: BackstageUserIdentity; +} + +// @public +export interface BackstageSignInResult { + // @deprecated entity?: Entity; + // @deprecated + id: string; + token: string; +} + +// @public +export type BackstageUserIdentity = { + type: 'user'; + userEntityRef: string; + ownershipEntityRefs: string[]; }; // Warning: (ae-missing-release-tag) "BitbucketOAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -185,10 +199,7 @@ export class CatalogIdentityClient { // Warning: (ae-forgotten-export) The symbol "UserQuery" needs to be exported by the entry point index.d.ts findUser(query: UserQuery): Promise; // Warning: (ae-forgotten-export) The symbol "MemberClaimQuery" needs to be exported by the entry point index.d.ts - resolveCatalogMembership({ - entityRefs, - logger, - }: MemberClaimQuery): Promise; + resolveCatalogMembership(query: MemberClaimQuery): Promise; } // Warning: (ae-missing-release-tag) "createAtlassianProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -270,13 +281,7 @@ export function createOriginFilter(config: Config): (origin: string) => boolean; // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createRouter({ - logger, - config, - discovery, - database, - providerFactories, -}: RouterOptions): Promise; +export function createRouter(options: RouterOptions): Promise; // @public (undocumented) export const createSamlProvider: ( @@ -361,7 +366,7 @@ export type GoogleProviderOptions = { // @public export class IdentityClient { constructor(options: { discovery: PluginEndpointDiscovery; issuer: string }); - authenticate(token: string | undefined): Promise; + authenticate(token: string | undefined): Promise; static getBearerToken( authorizationHeader: string | undefined, ): string | undefined; @@ -448,7 +453,7 @@ export interface OAuthHandlers { // 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-type) The @param block should not include a JSDoc-style '{type}' handler(req: express.Request): Promise<{ - response: AuthResponse; + response: OAuthResponse; refreshToken?: string; }>; logout?(): Promise; @@ -456,7 +461,7 @@ export interface OAuthHandlers { // 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-type) The @param block should not include a JSDoc-style '{type}' - refresh?(req: OAuthRefreshRequest): Promise>; + refresh?(req: OAuthRefreshRequest): Promise; // 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-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 @@ -491,10 +496,12 @@ export type OAuthRefreshRequest = express.Request<{}> & { refreshToken: string; }; -// Warning: (ae-missing-release-tag) "OAuthResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type OAuthResponse = AuthResponse; +// @public +export type OAuthResponse = { + profile: ProfileInfo; + providerInfo: OAuthProviderInfo; + backstageIdentity?: BackstageSignInResult; +}; // Warning: (ae-missing-release-tag) "OAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -551,8 +558,11 @@ export const postMessageResponse: ( response: WebMessageResponse, ) => void; -// Warning: (ae-missing-release-tag) "ProfileInfo" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// +// @public +export function prepareBackstageIdentityResponse( + result: BackstageSignInResult, +): BackstageIdentityResponse; + // @public export type ProfileInfo = { email?: string; @@ -637,5 +647,4 @@ export type WebMessageResponse = // src/providers/github/provider.d.ts:71:68 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" // src/providers/github/provider.d.ts:78:5 - (ae-forgotten-export) The symbol "StateEncoder" needs to be exported by the entry point index.d.ts // src/providers/types.d.ts:100:5 - (ae-forgotten-export) The symbol "AuthProviderConfig" needs to be exported by the entry point index.d.ts -// src/providers/types.d.ts:122:8 - (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative ``` diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 6f95c9850a..b2822c4f33 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.4.10", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", - "@backstage/test-utils": "^0.1.23", + "@backstage/test-utils": "^0.1.24", "@google-cloud/firestore": "^4.15.1", "@types/express": "^4.17.6", "@types/passport": "^1.0.3", @@ -73,7 +73,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/auth-backend/src/identity/IdentityClient.test.ts b/plugins/auth-backend/src/identity/IdentityClient.test.ts index 5eca6bf8cd..9f5e1ce489 100644 --- a/plugins/auth-backend/src/identity/IdentityClient.test.ts +++ b/plugins/auth-backend/src/identity/IdentityClient.test.ts @@ -96,7 +96,15 @@ describe('IdentityClient', () => { it('should accept fresh token', async () => { const token = await factory.issueToken({ claims: { sub: 'foo' } }); const response = await client.authenticate(token); - expect(response).toEqual({ id: 'foo', idToken: token }); + expect(response).toEqual({ + id: 'foo', + token: token, + identity: { + ownershipEntityRefs: [], + type: 'user', + userEntityRef: 'foo', + }, + }); }); it('should throw on incorrect issuer', async () => { @@ -159,7 +167,15 @@ describe('IdentityClient', () => { jest.spyOn(Date, 'now').mockImplementation(() => fixedTime); const token = await factory.issueToken({ claims: { sub: 'foo' } }); const response = await client.authenticate(token); - expect(response).toEqual({ id: 'foo', idToken: token }); + expect(response).toEqual({ + id: 'foo', + token: token, + identity: { + ownershipEntityRefs: [], + type: 'user', + userEntityRef: 'foo', + }, + }); }); it('should not be fooled by the none algorithm', async () => { diff --git a/plugins/auth-backend/src/identity/IdentityClient.ts b/plugins/auth-backend/src/identity/IdentityClient.ts index d60829bf59..552d231e1f 100644 --- a/plugins/auth-backend/src/identity/IdentityClient.ts +++ b/plugins/auth-backend/src/identity/IdentityClient.ts @@ -16,8 +16,9 @@ import fetch from 'node-fetch'; import { JWK, JWT, JWKS, JSONWebKey } from 'jose'; -import { BackstageIdentity } from '../providers'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { AuthenticationError } from '@backstage/errors'; +import { BackstageIdentityResponse } from '../providers/types'; const CLOCK_MARGIN_S = 10; @@ -45,15 +46,17 @@ export class IdentityClient { * Returns a BackstageIdentity (user) matching the token. * The method throws an error if verification fails. */ - async authenticate(token: string | undefined): Promise { + async authenticate( + token: string | undefined, + ): Promise { // Extract token from header if (!token) { - throw new Error('No token specified'); + throw new AuthenticationError('No token specified'); } // Get signing key matching token const key = await this.getKey(token); if (!key) { - throw new Error('No signing key matching token found'); + throw new AuthenticationError('No signing key matching token found'); } // Verify token claims and signature // Note: Claims must match those set by TokenFactory when issuing tokens @@ -62,12 +65,21 @@ export class IdentityClient { algorithms: ['ES256'], audience: 'backstage', issuer: this.issuer, - }) as { sub: string }; + }) as { sub: string; ent: string[] }; // Verified, return the matching user as BackstageIdentity // TODO: Settle internal user format/properties - const user: BackstageIdentity = { + if (!decoded.sub) { + throw new AuthenticationError('No user sub found in token'); + } + + const user: BackstageIdentityResponse = { id: decoded.sub, - idToken: token, + token, + identity: { + type: 'user', + userEntityRef: decoded.sub, + ownershipEntityRefs: decoded.ent ?? [], + }, }; return user; } diff --git a/plugins/auth-backend/src/index.ts b/plugins/auth-backend/src/index.ts index 894f8c1e55..66c1b42dd9 100644 --- a/plugins/auth-backend/src/index.ts +++ b/plugins/auth-backend/src/index.ts @@ -29,7 +29,7 @@ export * from './providers'; // ensuresXRequestedWith and postMessageResponse to safely handle CORS requests for login. The WebMessageResponse type in flow is used to type the response from the login-popup export * from './lib/flow'; -// OAuth wrapper over a passport or a custom `startegy`. +// OAuth wrapper over a passport or a custom `strategy`. export * from './lib/oauth'; export * from './lib/catalog'; diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index 02fe9818cb..a1f915d152 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -84,10 +84,8 @@ export class CatalogIdentityClient { * * Returns a superset of the entity names that can be passed directly to `issueToken` as `ent`. */ - async resolveCatalogMembership({ - entityRefs, - logger, - }: MemberClaimQuery): Promise { + async resolveCatalogMembership(query: MemberClaimQuery): Promise { + const { entityRefs, logger } = query; const resolvedEntityRefs = entityRefs .map((ref: string) => { try { diff --git a/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts b/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts index 117f1b86e4..07c8196dd2 100644 --- a/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts +++ b/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts @@ -51,7 +51,12 @@ describe('oauth helpers', () => { }, backstageIdentity: { id: 'a', - idToken: 'a.b.c', + token: 'a.b.c', + identity: { + type: 'user', + ownershipEntityRefs: [], + userEntityRef: 'a', + }, }, }, }; @@ -106,7 +111,12 @@ describe('oauth helpers', () => { }, backstageIdentity: { id: 'a', - idToken: 'a.b.c', + token: 'a.b.c', + identity: { + type: 'user', + ownershipEntityRefs: [], + userEntityRef: 'a', + }, }, }, }; @@ -148,7 +158,12 @@ describe('oauth helpers', () => { }, backstageIdentity: { id: 'a', - idToken: 'a.b.c', + token: 'a.b.c', + identity: { + type: 'user', + ownershipEntityRefs: [], + userEntityRef: 'a', + }, }, }, }; diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index fa61d69d80..92c76b04b7 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -31,6 +31,8 @@ const mockResponseData = { }, backstageIdentity: { id: 'foo', + token: + 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob', }, }; @@ -217,7 +219,13 @@ describe('OAuthAdapter', () => { ...mockResponseData, backstageIdentity: { id: mockResponseData.backstageIdentity.id, - token: 'my-id-token', + token: mockResponseData.backstageIdentity.token, + idToken: mockResponseData.backstageIdentity.token, + identity: { + ownershipEntityRefs: ['user:default/jimmymarkum'], + type: 'user', + userEntityRef: 'jimmymarkum', + }, }, }); }); diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index e1a6fdf2f9..eb3f7efa42 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -19,8 +19,9 @@ import crypto from 'crypto'; import { URL } from 'url'; import { AuthProviderRouteHandlers, - BackstageIdentity, AuthProviderConfig, + BackstageIdentityResponse, + BackstageSignInResult, } from '../../providers/types'; import { AuthenticationError, @@ -37,6 +38,7 @@ import { OAuthRefreshRequest, OAuthState, } from './types'; +import { prepareBackstageIdentityResponse } from '../../providers/prepareBackstageIdentityResponse'; export const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000; export const TEN_MINUTES_MS = 600 * 1000; @@ -150,12 +152,12 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { this.setRefreshTokenCookie(res, refreshToken); } - await this.populateIdentity(response.backstageIdentity); + const identity = await this.populateIdentity(response.backstageIdentity); // post message back to popup if successful return postMessageResponse(res, appOrigin, { type: 'authorization_response', - response, + response: { ...response, backstageIdentity: identity }, }); } catch (error) { const { name, message } = isError(error) @@ -209,7 +211,9 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { forwardReq as OAuthRefreshRequest, ); - await this.populateIdentity(response.backstageIdentity); + const backstageIdentity = await this.populateIdentity( + response.backstageIdentity, + ); if ( response.providerInfo.refreshToken && @@ -218,7 +222,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { this.setRefreshTokenCookie(res, response.providerInfo.refreshToken); } - res.status(200).json(response); + res.status(200).json({ ...response, backstageIdentity }); } catch (error) { throw new AuthenticationError('Refresh failed', error); } @@ -228,18 +232,22 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { * If the response from the OAuth provider includes a Backstage identity, we * make sure it's populated with all the information we can derive from the user ID. */ - private async populateIdentity(identity?: BackstageIdentity) { + private async populateIdentity( + identity?: BackstageSignInResult, + ): Promise { if (!identity) { - return; + return undefined; } - if (!(identity.token || identity.idToken)) { - identity.token = await this.options.tokenIssuer.issueToken({ - claims: { sub: identity.id }, - }); - } else if (!identity.token && identity.idToken) { - identity.token = identity.idToken; + if (identity.token) { + return prepareBackstageIdentityResponse(identity); } + + const token = await this.options.tokenIssuer.issueToken({ + claims: { sub: identity.id }, + }); + + return prepareBackstageIdentityResponse({ ...identity, token }); } private setNonceCookie = (res: express.Response, nonce: string) => { diff --git a/plugins/auth-backend/src/lib/oauth/types.ts b/plugins/auth-backend/src/lib/oauth/types.ts index 7912dd16a5..cd1439b399 100644 --- a/plugins/auth-backend/src/lib/oauth/types.ts +++ b/plugins/auth-backend/src/lib/oauth/types.ts @@ -16,7 +16,11 @@ import express from 'express'; import { Profile as PassportProfile } from 'passport'; -import { AuthResponse, RedirectInfo } from '../../providers/types'; +import { + RedirectInfo, + BackstageSignInResult, + ProfileInfo, +} from '../../providers/types'; /** * Common options for passport.js-based OAuth providers @@ -47,7 +51,16 @@ export type OAuthResult = { refreshToken?: string; }; -export type OAuthResponse = AuthResponse; +/** + * The expected response from an OAuth flow. + * + * @public + */ +export type OAuthResponse = { + profile: ProfileInfo; + providerInfo: OAuthProviderInfo; + backstageIdentity?: BackstageSignInResult; +}; export type OAuthProviderInfo = { /** @@ -108,7 +121,7 @@ export interface OAuthHandlers { * @param {express.Request} req */ handler(req: express.Request): Promise<{ - response: AuthResponse; + response: OAuthResponse; refreshToken?: string; }>; @@ -117,7 +130,7 @@ export interface OAuthHandlers { * @param {string} refreshToken * @param {string} scope */ - refresh?(req: OAuthRefreshRequest): Promise>; + refresh?(req: OAuthRefreshRequest): Promise; /** * (Optional) Sign out of the auth provider. diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 4cc3f33499..7aa98c3e65 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -151,7 +151,7 @@ export class Auth0AuthProvider implements OAuthHandlers { const id = profile.email.split('@')[0]; - return { ...response, backstageIdentity: { id } }; + return { ...response, backstageIdentity: { id, token: '' } }; } } diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts index 3f72004d48..048128f942 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts @@ -122,7 +122,11 @@ describe('AwsAlbAuthProvider', () => { profile: makeProfileInfo(fullProfile), }), signInResolver: async () => { - return { id: 'user.name', token: 'TOKEN' }; + return { + id: 'user.name', + token: + 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob', + }; }, }); @@ -133,7 +137,15 @@ describe('AwsAlbAuthProvider', () => { expect(mockResponse.json).toHaveBeenCalledWith({ backstageIdentity: { id: 'user.name', - token: 'TOKEN', + token: + 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob', + idToken: + 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob', + identity: { + ownershipEntityRefs: ['user:default/jimmymarkum'], + type: 'user', + userEntityRef: 'jimmymarkum', + }, }, profile: { displayName: 'User Name', diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.ts b/plugins/auth-backend/src/providers/aws-alb/provider.ts index b0b9070d50..114bc9a204 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.ts @@ -32,6 +32,7 @@ import { CatalogIdentityClient } from '../../lib/catalog'; import { Profile as PassportProfile } from 'passport'; import { makeProfileInfo } from '../../lib/passport'; import { AuthenticationError } from '@backstage/errors'; +import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse'; export const ALB_JWT_HEADER = 'x-amzn-oidc-data'; export const ALB_ACCESSTOKEN_HEADER = 'x-amzn-oidc-accesstoken'; @@ -198,7 +199,7 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers { accessToken: result.accessToken, expiresInSeconds: result.expiresInSeconds, }, - backstageIdentity, + backstageIdentity: prepareBackstageIdentityResponse(backstageIdentity), profile, }; } diff --git a/plugins/auth-backend/src/providers/index.ts b/plugins/auth-backend/src/providers/index.ts index 88c6ecb6fe..4ecbb98fd2 100644 --- a/plugins/auth-backend/src/providers/index.ts +++ b/plugins/auth-backend/src/providers/index.ts @@ -38,4 +38,13 @@ export type { // These types are needed for a postMessage from the login pop-up // to the frontend -export type { AuthResponse, BackstageIdentity, ProfileInfo } from './types'; +export type { + AuthResponse, + BackstageIdentity, + BackstageUserIdentity, + BackstageIdentityResponse, + BackstageSignInResult, + ProfileInfo, +} from './types'; + +export { prepareBackstageIdentityResponse } from './prepareBackstageIdentityResponse'; diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index 1160ad19c9..2f9c739860 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -59,6 +59,7 @@ export type OAuth2AuthProviderOptions = OAuthProviderOptions & { tokenUrl: string; scope?: string; logger: Logger; + includeBasicAuth?: boolean; }; export class OAuth2AuthProvider implements OAuthHandlers { @@ -85,12 +86,14 @@ export class OAuth2AuthProvider implements OAuthHandlers { tokenURL: options.tokenUrl, passReqToCallback: false as true, scope: options.scope, - customHeaders: { - Authorization: `Basic ${this.encodeClientCredentials( - options.clientId, - options.clientSecret, - )}`, - }, + customHeaders: options.includeBasicAuth + ? { + Authorization: `Basic ${this.encodeClientCredentials( + options.clientId, + options.clientSecret, + )}`, + } + : undefined, }, ( accessToken: any, @@ -244,6 +247,7 @@ export const createOAuth2Provider = ( const authorizationUrl = envConfig.getString('authorizationUrl'); const tokenUrl = envConfig.getString('tokenUrl'); const scope = envConfig.getOptionalString('scope'); + const includeBasicAuth = envConfig.getOptionalBoolean('includeBasicAuth'); const disableRefresh = envConfig.getOptionalBoolean('disableRefresh') ?? false; @@ -280,6 +284,7 @@ export const createOAuth2Provider = ( tokenUrl, scope, logger, + includeBasicAuth, }); return OAuthAdapter.fromConfig(globalConfig, provider, { diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index eba9c72e41..158af6f830 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -205,6 +205,7 @@ export class OidcAuthProvider implements OAuthHandlers { }, ); } + return response; } } diff --git a/plugins/auth-backend/src/providers/onelogin/provider.ts b/plugins/auth-backend/src/providers/onelogin/provider.ts index 092d22189d..66e8b0bfc5 100644 --- a/plugins/auth-backend/src/providers/onelogin/provider.ts +++ b/plugins/auth-backend/src/providers/onelogin/provider.ts @@ -148,7 +148,7 @@ export class OneLoginProvider implements OAuthHandlers { const id = profile.email.split('@')[0]; - return { ...response, backstageIdentity: { id } }; + return { ...response, backstageIdentity: { id, token: '' } }; } } diff --git a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts new file mode 100644 index 0000000000..31df7a4cef --- /dev/null +++ b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 { BackstageIdentityResponse, BackstageSignInResult } from './types'; + +function parseJwtPayload(token: string) { + const [_header, payload, _signature] = token.split('.'); + return JSON.parse(Buffer.from(payload, 'base64').toString()); +} + +/** + * Parses token and decorates the BackstageIdentityResponse with identity information sourced from the token + * + * @public + */ +export function prepareBackstageIdentityResponse( + result: BackstageSignInResult, +): BackstageIdentityResponse { + const { sub, ent } = parseJwtPayload(result.token); + return { + ...{ + // TODO: idToken is for backwards compatibility and can be removed in the future + idToken: result.token, + ...result, + }, + identity: { + type: 'user', + userEntityRef: sub, + ownershipEntityRefs: ent ?? [], + }, + }; +} diff --git a/plugins/auth-backend/src/providers/saml/provider.ts b/plugins/auth-backend/src/providers/saml/provider.ts index 3ab00ce401..8a4afd1fa6 100644 --- a/plugins/auth-backend/src/providers/saml/provider.ts +++ b/plugins/auth-backend/src/providers/saml/provider.ts @@ -38,6 +38,7 @@ import { TokenIssuer } from '../../identity/types'; import { isError } from '@backstage/errors'; import { CatalogIdentityClient } from '../../lib/catalog'; import { Logger } from 'winston'; +import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse'; /** @public */ export type SamlAuthResult = { @@ -105,7 +106,7 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers { }; if (this.signInResolver) { - response.backstageIdentity = await this.signInResolver( + const signInResponse = await this.signInResolver( { result, profile, @@ -116,6 +117,9 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers { logger: this.logger, }, ); + + response.backstageIdentity = + prepareBackstageIdentityResponse(signInResponse); } return postMessageResponse(res, this.appUrl, { diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 089c82b293..dafa52163c 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -137,42 +137,92 @@ export type AuthProviderFactory = ( export type AuthResponse = { providerInfo: ProviderInfo; profile: ProfileInfo; - backstageIdentity?: BackstageIdentity; + backstageIdentity?: BackstageIdentityResponse; }; -export type BackstageIdentity = { +/** + * User identity information within Backstage. + * + * @public + */ +export type BackstageUserIdentity = { + /** + * The type of identity that this structure represents. In the frontend app + * this will currently always be 'user'. + */ + type: 'user'; + + /** + * The entityRef of the user in the catalog. + * For example User:default/sandra + */ + userEntityRef: string; + + /** + * The user and group entities that the user claims ownership through + */ + ownershipEntityRefs: string[]; +}; + +/** + * A representation of a successful Backstage sign-in. + * + * Compared to the {@link BackstageIdentityResponse} this type omits + * the decoded identity information embedded in the token. + * + * @public + */ +export interface BackstageSignInResult { /** * An opaque ID that uniquely identifies the user within Backstage. * * This is typically the same as the user entity `metadata.name`. + * + * @deprecated Use the `identity` field instead */ id: string; - /** - * This is deprecated, use `token` instead. - * @deprecated - */ - idToken?: string; - - /** - * The token used to authenticate the user within Backstage. - */ - token?: string; - /** * The entity that the user is represented by within Backstage. * * This entity may or may not exist within the Catalog, and it can be used * to read and store additional metadata about the user. + * + * @deprecated Use the `identity` field instead. */ entity?: Entity; -}; + + /** + * The token used to authenticate the user within Backstage. + */ + token: string; +} + +/** + * The old exported symbol for {@link BackstageSignInResult}. + * @public + * @deprecated Use the `BackstageSignInResult` type instead. + */ +export type BackstageIdentity = BackstageSignInResult; + +/** + * Response object containing the {@link BackstageUserIdentity} and the token from the authentication provider. + * @public + */ +export interface BackstageIdentityResponse extends BackstageSignInResult { + /** + * A plaintext description of the identity that is encapsulated within the token. + */ + identity: BackstageUserIdentity; +} /** * Used to display login information to user, i.e. sidebar popup. * * It is also temporarily used as the profile of the signed-in user's Backstage * identity, but we want to replace that with data from identity and/org catalog service + * + * @public */ export type ProfileInfo = { /** @@ -209,7 +259,7 @@ export type SignInResolver = ( catalogIdentityClient: CatalogIdentityClient; logger: Logger; }, -) => Promise; +) => Promise; export type AuthHandlerResult = { profile: ProfileInfo }; diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 4aa9ed8778..6a96d421da 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -44,13 +44,10 @@ export interface RouterOptions { providerFactories?: ProviderFactories; } -export async function createRouter({ - logger, - config, - discovery, - database, - providerFactories, -}: RouterOptions): Promise { +export async function createRouter( + options: RouterOptions, +): Promise { + const { logger, config, discovery, database, providerFactories } = options; const router = Router(); const appUrl = config.getString('app.baseUrl'); diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index 9c94a04a68..e0e74a9bc6 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-azure-devops-backend +## 0.2.4 + +### Patch Changes + +- a77526afcd: Added getting builds by definition name +- Updated dependencies + - @backstage/backend-common@0.9.13 + - @backstage/plugin-azure-devops-common@0.1.2 + ## 0.2.3 ### Patch Changes diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md index 19d96dc728..9574215e3e 100644 --- a/plugins/azure-devops-backend/api-report.md +++ b/plugins/azure-devops-backend/api-report.md @@ -4,6 +4,8 @@ ```ts import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { BuildDefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { BuildRun } from '@backstage/plugin-azure-devops-common'; import { Config } from '@backstage/config'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; import express from 'express'; @@ -23,12 +25,31 @@ export class AzureDevOpsApi { // (undocumented) getAllTeams(): Promise; // (undocumented) + getBuildDefinitions( + projectName: string, + definitionName: string, + ): Promise; + // (undocumented) getBuildList( projectName: string, repoId: string, top: number, ): Promise; // (undocumented) + getBuildRuns( + projectName: string, + top: number, + repoName?: string, + definitionName?: string, + ): Promise; + // (undocumented) + getBuilds( + projectName: string, + top: number, + repoId?: string, + definitions?: number[], + ): Promise; + // (undocumented) getDashboardPullRequests( projectName: string, options: PullRequestOptions, diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index c587f97837..9741380fb1 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/config": "^0.1.11", - "@backstage/plugin-azure-devops-common": "^0.1.1", + "@backstage/plugin-azure-devops-common": "^0.1.2", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", "express": "^4.17.1", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "msw": "^0.35.0" diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts index 2cb7d93c0b..76b5089bbc 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts @@ -29,277 +29,510 @@ import { GitPullRequest, GitRepository, } from 'azure-devops-node-api/interfaces/GitInterfaces'; -import { mappedPullRequest, mappedRepoBuild } from './AzureDevOpsApi'; +import { + mappedBuildRun, + mappedPullRequest, + mappedRepoBuild, +} from './AzureDevOpsApi'; import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; describe('AzureDevOpsApi', () => { describe('mappedRepoBuild', () => { - it('should return RepoBuild from Build', () => { - const inputBuildDefinition: DefinitionReference = { - name: 'My Build Definition', - }; + describe('mappedRepoBuild happy path', () => { + it('should return RepoBuild from Build', () => { + const inputBuildDefinition: DefinitionReference = { + name: 'My Build Definition', + }; - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: inputBuildDefinition, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: inputBuildDefinition, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'My Build Definition - Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'My Build Definition - Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); }); - }); - describe('mappedRepoBuild with no Build definition name', () => { - it('should return RepoBuild with only Build Number for title', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + describe('mappedRepoBuild with no Build definition name', () => { + it('should return RepoBuild with only Build Number for title', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); }); - }); - describe('mappedRepoBuild with undefined status', () => { - it('should return BuildStatus of None for status', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + describe('mappedRepoBuild with undefined status', () => { + it('should return BuildStatus of None for status', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: undefined, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: undefined, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.None, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.None, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); }); - }); - describe('mappedRepoBuild with undefined result', () => { - it('should return BuildResult of None for result', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + describe('mappedRepoBuild with undefined result', () => { + it('should return BuildResult of None for result', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); }); - }); - describe('mappedRepoBuild with undefined link', () => { - it('should return empty string for link', () => { - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + describe('mappedRepoBuild with undefined link', () => { + it('should return empty string for link', () => { + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: undefined, - requestedFor: inputIdentityRef, - }; + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: undefined, + requestedFor: inputIdentityRef, + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: '', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); }); }); describe('mappedPullRequest', () => { - it('should return PullRequest from GitPullRequest', () => { - const inputGitRepository: GitRepository = { - name: 'super-feature-repo', - }; + describe('mappedPullRequest happy path', () => { + it('should return PullRequest from GitPullRequest', () => { + const inputGitRepository: GitRepository = { + name: 'super-feature-repo', + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; - const inputPullRequest: GitPullRequest = { - pullRequestId: 7181, - repository: inputGitRepository, - title: 'My Awesome New Feature', - createdBy: inputIdentityRef, - creationDate: new Date('2020-09-12T06:10:23.932Z'), - sourceRefName: 'refs/heads/topic/super-awesome-feature', - targetRefName: 'refs/heads/main', - status: PullRequestStatus.Active, - isDraft: false, - }; + const inputPullRequest: GitPullRequest = { + pullRequestId: 7181, + repository: inputGitRepository, + title: 'My Awesome New Feature', + createdBy: inputIdentityRef, + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/super-awesome-feature', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }; - const inputBaseUrl = - 'https://host.com/myOrg/_git/super-feature-repo/pullrequest'; + const inputBaseUrl = + 'https://host.com/myOrg/_git/super-feature-repo/pullrequest'; - const outputPullRequest: PullRequest = { - pullRequestId: 7181, - repoName: 'super-feature-repo', - title: 'My Awesome New Feature', - uniqueName: 'DOMAIN\\jdoe', - createdBy: 'Jane Doe', - creationDate: '2020-09-12T06:10:23.932Z', - sourceRefName: 'refs/heads/topic/super-awesome-feature', - targetRefName: 'refs/heads/main', - status: PullRequestStatus.Active, - isDraft: false, - link: 'https://host.com/myOrg/_git/super-feature-repo/pullrequest/7181', - }; + const outputPullRequest: PullRequest = { + pullRequestId: 7181, + repoName: 'super-feature-repo', + title: 'My Awesome New Feature', + uniqueName: 'DOMAIN\\jdoe', + createdBy: 'Jane Doe', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/super-awesome-feature', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'https://host.com/myOrg/_git/super-feature-repo/pullrequest/7181', + }; - expect(mappedPullRequest(inputPullRequest, inputBaseUrl)).toEqual( - outputPullRequest, - ); + expect(mappedPullRequest(inputPullRequest, inputBaseUrl)).toEqual( + outputPullRequest, + ); + }); + }); + }); + + describe('mappedBuildRun', () => { + describe('mappedBuildRun happy path', () => { + it('should return RepoBuild from Build', () => { + const inputBuildDefinition: DefinitionReference = { + name: 'My Build Definition', + }; + + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: inputBuildDefinition, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'My Build Definition - Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with no Build definition name', () => { + it('should return RepoBuild with only Build Number for title', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined status', () => { + it('should return BuildStatus of None for status', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: undefined, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.None, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined result', () => { + it('should return BuildResult of None for result', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined link', () => { + it('should return empty string for link', () => { + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: undefined, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); }); }); }); diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index 53dc19c68d..6e45a5f4e5 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -14,8 +14,13 @@ * limitations under the License. */ +import { + Build, + BuildDefinitionReference, +} from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildResult, + BuildRun, BuildStatus, DashboardPullRequest, Policy, @@ -35,7 +40,6 @@ import { getArtifactId, } from '../utils'; -import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; import { TeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; @@ -258,6 +262,85 @@ export class AzureDevOpsApi { .map(teamMember => teamMember.identity?.id) .filter((id): id is string => Boolean(id)); } + + public async getBuildDefinitions( + projectName: string, + definitionName: string, + ): Promise { + this.logger?.debug( + `Calling Azure DevOps REST API, getting Build Definitions for ${definitionName} in Project ${projectName}`, + ); + + const client = await this.webApi.getBuildApi(); + return client.getDefinitions(projectName, definitionName); + } + + public async getBuilds( + projectName: string, + top: number, + repoId?: string, + definitions?: number[], + ): Promise { + this.logger?.debug( + `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, + ); + + const client = await this.webApi.getBuildApi(); + return client.getBuilds( + projectName, + definitions, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + top, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + repoId, + repoId ? 'TfsGit' : undefined, + ); + } + + public async getBuildRuns( + projectName: string, + top: number, + repoName?: string, + definitionName?: string, + ) { + let repoId: string | undefined; + let definitions: number[] | undefined; + + if (repoName) { + const gitRepository = await this.getGitRepository(projectName, repoName); + repoId = gitRepository.id; + } + + if (definitionName) { + const buildDefinitions = await this.getBuildDefinitions( + projectName, + definitionName, + ); + definitions = buildDefinitions + .map(bd => bd.id) + .filter((bd): bd is number => Boolean(bd)); + } + + const builds = await this.getBuilds(projectName, top, repoId, definitions); + + const buildRuns: BuildRun[] = builds.map(mappedBuildRun); + + return buildRuns; + } } export function mappedRepoBuild(build: Build): RepoBuild { @@ -295,3 +378,20 @@ export function mappedPullRequest( link: `${linkBaseUrl}/${pullRequest.pullRequestId}`, }; } + +export function mappedBuildRun(build: Build): BuildRun { + return { + id: build.id, + title: [build.definition?.name, build.buildNumber] + .filter(Boolean) + .join(' - '), + link: build._links?.web.href ?? '', + status: build.status ?? BuildStatus.None, + result: build.result ?? BuildResult.None, + queueTime: build.queueTime?.toISOString(), + startTime: build.startTime?.toISOString(), + finishTime: build.finishTime?.toISOString(), + source: `${build.sourceBranch} (${build.sourceVersion?.substr(0, 8)})`, + uniqueName: build.requestedFor?.uniqueName ?? 'N/A', + }; +} diff --git a/plugins/azure-devops-backend/src/service/router.test.ts b/plugins/azure-devops-backend/src/service/router.test.ts index ce5f712392..87135781e6 100644 --- a/plugins/azure-devops-backend/src/service/router.test.ts +++ b/plugins/azure-devops-backend/src/service/router.test.ts @@ -14,8 +14,13 @@ * limitations under the License. */ +import { + Build, + BuildDefinitionReference, +} from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildResult, + BuildRun, BuildStatus, PullRequest, PullRequestStatus, @@ -23,7 +28,6 @@ import { } from '@backstage/plugin-azure-devops-common'; import { AzureDevOpsApi } from '../api'; -import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { ConfigReader } from '@backstage/config'; import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { createRouter } from './router'; @@ -39,8 +43,12 @@ describe('createRouter', () => { azureDevOpsApi = { getGitRepository: jest.fn(), getBuildList: jest.fn(), + getBuildDefinitions: jest.fn(), getRepoBuilds: jest.fn(), + getDefinitionBuilds: jest.fn(), getPullRequests: jest.fn(), + getBuilds: jest.fn(), + getBuildRuns: jest.fn(), } as any; const router = await createRouter({ azureDevOpsApi, @@ -260,4 +268,142 @@ describe('createRouter', () => { expect(response.body).toEqual(pullRequests); }); }); + + describe('GET /build-definitions/:projectName/:definitionName', () => { + it('fetches a list of build definitions', async () => { + const inputDefinition: BuildDefinitionReference = { + id: 1, + name: 'myBuildDefinition', + }; + + const inputDefinitions: BuildDefinitionReference[] = [inputDefinition]; + + azureDevOpsApi.getBuildDefinitions.mockResolvedValueOnce( + inputDefinitions, + ); + + const response = await request(app).get( + '/build-definitions/myProject/myBuildDefinition', + ); + + expect(azureDevOpsApi.getBuildDefinitions).toHaveBeenCalledWith( + 'myProject', + 'myBuildDefinition', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(inputDefinitions); + }); + }); + + describe('GET /builds/:projectName', () => { + describe('GET /builds/:projectName with repoName', () => { + it('fetches a list of build runs using repoName', async () => { + const firstBuildRun: BuildRun = { + id: 1, + title: 'My Build Definition - Build 1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.PartiallySucceeded, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + }; + + const secondBuildRun: BuildRun = { + id: 2, + title: 'My Build Definition - Build 2', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=2', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (13c988d4)', + }; + + const thirdBuildRun: BuildRun = { + id: 3, + title: 'My Build Definition - Build 3', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (9bedf678)', + }; + + const buildRuns: BuildRun[] = [ + firstBuildRun, + secondBuildRun, + thirdBuildRun, + ]; + + azureDevOpsApi.getBuildRuns.mockResolvedValueOnce(buildRuns); + + const response = await request(app) + .get('/builds/myProject') + .query({ top: '50', repoName: 'myRepo' }); + + expect(azureDevOpsApi.getBuildRuns).toHaveBeenCalledWith( + 'myProject', + 50, + 'myRepo', + undefined, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(buildRuns); + }); + }); + + describe('GET /builds/:projectName with definitionName', () => { + it('fetches a list of build runs using definitionName', async () => { + const firstBuildRun: BuildRun = { + id: 1, + title: 'My Build Definition - Build 1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.PartiallySucceeded, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + }; + + const secondBuildRun: BuildRun = { + id: 2, + title: 'My Build Definition - Build 2', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=2', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (13c988d4)', + }; + + const thirdBuildRun: BuildRun = { + id: 3, + title: 'My Build Definition - Build 3', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + source: 'refs/heads/develop (9bedf678)', + }; + + const buildRuns: BuildRun[] = [ + firstBuildRun, + secondBuildRun, + thirdBuildRun, + ]; + + azureDevOpsApi.getBuildRuns.mockResolvedValueOnce(buildRuns); + + const response = await request(app) + .get('/builds/myProject') + .query({ top: '50', definitionName: 'myDefinition' }); + + expect(azureDevOpsApi.getBuildRuns).toHaveBeenCalledWith( + 'myProject', + 50, + undefined, + 'myDefinition', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(buildRuns); + }); + }); + }); }); diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index 57d54df18f..99c140a424 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -144,6 +144,32 @@ export async function createRouter( res.status(200).json(allTeams); }); + router.get( + '/build-definitions/:projectName/:definitionName', + async (req, res) => { + const { projectName, definitionName } = req.params; + const buildDefinitionList = await azureDevOpsApi.getBuildDefinitions( + projectName, + definitionName, + ); + res.status(200).json(buildDefinitionList); + }, + ); + + router.get('/builds/:projectName', async (req, res) => { + const { projectName } = req.params; + const repoName = req.query.repoName?.toString(); + const definitionName = req.query.definitionName?.toString(); + const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; + const builds = await azureDevOpsApi.getBuildRuns( + projectName, + top, + repoName, + definitionName, + ); + res.status(200).json(builds); + }); + router.use(errorHandler()); return router; } diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index 7b2c1be0e7..b2c8645e94 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-azure-devops-common +## 0.1.2 + +### Patch Changes + +- a77526afcd: Added getting builds by definition name + ## 0.1.1 ### Patch Changes diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md index 17cccb05cb..bb458f169a 100644 --- a/plugins/azure-devops-common/api-report.md +++ b/plugins/azure-devops-common/api-report.md @@ -14,6 +14,29 @@ export enum BuildResult { Succeeded = 2, } +// Warning: (ae-missing-release-tag) "BuildRun" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type BuildRun = { + id?: number; + title: string; + link?: string; + status?: BuildStatus; + result?: BuildResult; + queueTime?: string; + startTime?: string; + finishTime?: string; + source: string; + uniqueName?: string; +}; + +// Warning: (ae-missing-release-tag) "BuildRunOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type BuildRunOptions = { + top?: number; +}; + // Warning: (ae-missing-release-tag) "BuildStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 0b64178a68..7b82296c40 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-common", - "version": "0.1.1", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.10.1" }, "files": [ "dist" diff --git a/plugins/azure-devops-common/src/types.ts b/plugins/azure-devops-common/src/types.ts index da41e08d1f..e6bd174079 100644 --- a/plugins/azure-devops-common/src/types.ts +++ b/plugins/azure-devops-common/src/types.ts @@ -251,3 +251,19 @@ export enum PullRequestVoteStatus { WaitingForAuthor = -5, Rejected = -10, } +export type BuildRun = { + id?: number; + title: string; + link?: string; + status?: BuildStatus; + result?: BuildResult; + queueTime?: string; + startTime?: string; + finishTime?: string; + source: string; + uniqueName?: string; +}; + +export type BuildRunOptions = { + top?: number; +}; diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 9f460d4837..57f80f508b 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-azure-devops +## 0.1.6 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + - @backstage/plugin-azure-devops-common@0.1.2 + ## 0.1.5 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 29f133ab5b..a37259739f 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.1.5", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,27 +28,28 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.4", - "@backstage/plugin-azure-devops-common": "^0.1.1", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-azure-devops-common": "^0.1.2", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "humanize-duration": "^3.27.0", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 449352f87b..049709e8be 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-badges +## 0.2.16 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.15 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 7c478c0a26..441f72c550 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.15", + "version": "0.2.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,24 +28,25 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.5", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 812ae8f5e3..2646731535 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-bazaar-backend +## 0.1.4 + +### Patch Changes + +- 210fcf63ee: Handle migration error when old data is present in the database +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.1.3 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index aec96bb021..aefe3bfdc6 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.1.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/backend-test-utils": "^0.1.10", "@backstage/config": "^0.1.5", "@types/express": "^4.17.6", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.10.1" }, "files": [ "dist", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 2a21310347..664b69a4a4 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-bazaar +## 0.1.6 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog@0.7.4 + - @backstage/plugin-catalog-react@0.6.5 + - @backstage/cli@0.10.1 + ## 0.1.5 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index 2defba5cca..3db79b9cdf 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.1.5", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,11 +22,11 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.0", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog": "^0.7.3", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/cli": "^0.10.1", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -34,15 +34,16 @@ "@material-ui/pickers": "^3.3.10", "@testing-library/jest-dom": "^5.10.1", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-hook-form": "^7.13.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/dev-utils": "^0.2.13", + "@backstage/cli": "^0.10.1", + "@backstage/dev-utils": "^0.2.14", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.0.6" }, diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 05f12c9fdd..43c2ba1ac6 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-bitrise +## 0.1.19 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.18 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index b036610f0a..35a0a9e079 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.18", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,9 +22,9 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -33,16 +33,17 @@ "lodash": "^4.17.21", "luxon": "^2.0.2", "qs": "^6.9.6", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4", "recharts": "^1.8.5" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 93e41cfddc..dc7fc50f76 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend +## 0.19.1 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- 6bccc7d794: The `pagedRequest` method in the GitLab ingestion client is now public for re-use and may be used to make other calls to the GitLab API. Developers can now pass in a type into the GitLab `paginated` and `pagedRequest` functions as generics instead of forcing `any` (defaults to `any` to maintain compatibility). The `GitLabClient` now provides a `isSelfManaged` convenience method. +- 0e4daaa753: Reject catalog entities that have duplicate fields that vary only in casing. +- 98a9c35f0c: Honor database migration configuration +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.19.0 ### Minor Changes diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 43eb8d61b7..f773905ca0 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -752,13 +752,7 @@ export type DbPageInfo = // // @public (undocumented) export class DefaultCatalogCollator implements DocumentCollator { - constructor({ - discovery, - locationTemplate, - filter, - catalogClient, - tokenManager, - }: { + constructor(options: { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; locationTemplate?: string; diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 694db42877..6cfb73a3d1 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "0.19.0", + "version": "0.19.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", @@ -63,8 +63,8 @@ }, "devDependencies": { "@backstage/backend-test-utils": "^0.1.10", - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", diff --git a/plugins/catalog-backend/src/ingestion/processors/gitlab/client.test.ts b/plugins/catalog-backend/src/ingestion/processors/gitlab/client.test.ts new file mode 100644 index 0000000000..b249137740 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/gitlab/client.test.ts @@ -0,0 +1,268 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { readGitLabIntegrationConfig } from '@backstage/integration'; +import { getVoidLogger } from '@backstage/backend-common'; +import { rest } from 'msw'; +import { setupServer, SetupServerApi } from 'msw/node'; + +import { GitLabClient, paginated } from './client'; + +const server = setupServer(); +setupRequestMockHandlers(server); + +const MOCK_CONFIG = readGitLabIntegrationConfig( + new ConfigReader({ + host: 'example.com', + token: 'test-token', + apiBaseUrl: 'https://example.com/api/v4', + }), +); +const FAKE_PAGED_ENDPOINT = `/some-endpoint`; +const FAKE_PAGED_URL = `${MOCK_CONFIG.apiBaseUrl}${FAKE_PAGED_ENDPOINT}`; + +function setupFakeFourPageURL(srv: SetupServerApi, url: string) { + srv.use( + rest.get(url, (req, res, ctx) => { + const page = req.url.searchParams.get('page'); + const currentPage = page ? Number(page) : 1; + const fakePageCount = 4; + + return res( + // set next page number header if page requested is less than count + ctx.set( + 'x-next-page', + currentPage < fakePageCount ? String(currentPage + 1) : '', + ), + ctx.json([{ someContentOfPage: currentPage }]), + ); + }), + ); +} + +function setupFakeGroupProjectsEndpoint( + srv: SetupServerApi, + apiBaseUrl: string, + groupID: string, +) { + srv.use( + rest.get(`${apiBaseUrl}/groups/${groupID}/projects`, (_, res, ctx) => { + return res( + ctx.set('x-next-page', ''), + ctx.json([ + { + id: 1, + description: 'Project One Description', + name: 'Project One', + path: 'project-one', + }, + ]), + ); + }), + ); +} + +function setupFakeInstanceProjectsEndpoint( + srv: SetupServerApi, + apiBaseUrl: string, +) { + srv.use( + rest.get(`${apiBaseUrl}/projects`, (_, res, ctx) => { + return res( + ctx.set('x-next-page', ''), + ctx.json([ + { + id: 1, + description: 'Project One Description', + name: 'Project One', + path: 'project-one', + }, + { + id: 2, + description: 'Project Two Description', + name: 'Project Two', + path: 'project-two', + }, + ]), + ); + }), + ); +} + +describe('GitLabClient', () => { + describe('isSelfManaged', () => { + it('returns true if self managed instance', () => { + const client = new GitLabClient({ + config: readGitLabIntegrationConfig( + new ConfigReader({ + host: 'example.com', + token: 'test-token', + apiBaseUrl: 'https://example.com/api/v4', + }), + ), + logger: getVoidLogger(), + }); + expect(client.isSelfManaged()).toBeTruthy(); + }); + it('returns false if gitlab.com', () => { + const client = new GitLabClient({ + config: readGitLabIntegrationConfig( + new ConfigReader({ + host: 'gitlab.com', + token: 'test-token', + }), + ), + logger: getVoidLogger(), + }); + expect(client.isSelfManaged()).toBeFalsy(); + }); + }); + + describe('pagedRequest', () => { + beforeEach(() => { + // setup fake paginated endpoint with 4 pages each returning one item + setupFakeFourPageURL(server, FAKE_PAGED_URL); + }); + + it('should provide immediate items within the page', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items } = await client.pagedRequest(FAKE_PAGED_ENDPOINT); + // fake page contains exactly one item + expect(items).toHaveLength(1); + }); + + it('should request items for a given page number', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const requestedPage = 2; + const { items, nextPage } = await client.pagedRequest( + FAKE_PAGED_ENDPOINT, + { + page: requestedPage, + }, + ); + // should contain an item from a given page + expect(items[0].someContentOfPage).toEqual(requestedPage); + // should set the nextPage property to the next page + expect(nextPage).toEqual(3); + }); + + it('should not have a next page if at the end', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items, nextPage } = await client.pagedRequest( + FAKE_PAGED_ENDPOINT, + { + page: 4, + }, + ); + // should contain item of last page + expect(items).toHaveLength(1); + expect(nextPage).toBeNull(); + }); + + it('should throw if response is not okay', async () => { + const endpoint = '/unhealthy-endpoint'; + const url = `${MOCK_CONFIG.apiBaseUrl}${endpoint}`; + server.use( + rest.get(url, (_, res, ctx) => { + return res(ctx.status(400), ctx.json({ error: 'some error' })); + }), + ); + + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + // non-200 status code should throw + await expect(() => client.pagedRequest(endpoint)).rejects.toThrowError(); + }); + }); + + describe('listProjects', () => { + it('should get projects for a given group', async () => { + setupFakeGroupProjectsEndpoint( + server, + MOCK_CONFIG.apiBaseUrl, + 'test-group', + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const groupProjectsGen = paginated( + options => client.listProjects(options), + { group: 'test-group' }, + ); + const allItems = []; + for await (const item of groupProjectsGen) { + allItems.push(item); + } + expect(allItems).toHaveLength(1); + }); + + it('should get all projects for an instance', async () => { + setupFakeInstanceProjectsEndpoint(server, MOCK_CONFIG.apiBaseUrl); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const instanceProjects = paginated( + options => client.listProjects(options), + {}, + ); + const allProjects = []; + for await (const project of instanceProjects) { + allProjects.push(project); + } + expect(allProjects).toHaveLength(2); + }); + }); +}); + +describe('paginated', () => { + it('should iterate through the pages until exhausted', async () => { + setupFakeFourPageURL(server, FAKE_PAGED_URL); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const paginatedItems = paginated( + options => client.pagedRequest(FAKE_PAGED_ENDPOINT, options), + {}, + ); + const allItems = []; + for await (const item of paginatedItems) { + allItems.push(item); + } + + expect(allItems).toHaveLength(4); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/processors/gitlab/client.ts b/plugins/catalog-backend/src/ingestion/processors/gitlab/client.ts index d1765521a3..4d42f5e068 100644 --- a/plugins/catalog-backend/src/ingestion/processors/gitlab/client.ts +++ b/plugins/catalog-backend/src/ingestion/processors/gitlab/client.ts @@ -21,6 +21,18 @@ import { } from '@backstage/integration'; import { Logger } from 'winston'; +export type ListOptions = { + [key: string]: string | number | boolean | undefined; + group?: string; + per_page?: number | undefined; + page?: number | undefined; +}; + +export type PagedResponse = { + items: T[]; + nextPage?: number; +}; + export class GitLabClient { private readonly config: GitLabIntegrationConfig; private readonly logger: Logger; @@ -30,12 +42,17 @@ export class GitLabClient { this.logger = options.logger; } + /** + * Indicates whether the client is for a SaaS or self managed GitLab instance. + */ + isSelfManaged(): boolean { + return this.config.host !== 'gitlab.com'; + } + async listProjects(options?: ListOptions): Promise> { if (options?.group) { return this.pagedRequest( - `${this.config.apiBaseUrl}/groups/${encodeURIComponent( - options?.group, - )}/projects`, + `/groups/${encodeURIComponent(options?.group)}/projects`, { ...options, include_subgroups: true, @@ -43,14 +60,26 @@ export class GitLabClient { ); } - return this.pagedRequest(`${this.config.apiBaseUrl}/projects`, options); + return this.pagedRequest(`/projects`, options); } - private async pagedRequest( + /** + * Performs a request against a given paginated GitLab endpoint. + * + * This method may be used to perform authenticated REST calls against any + * paginated GitLab endpoint which uses X-NEXT-PAGE headers. The return value + * can be be used with the {@link paginated} async-generator function to yield + * each item from the paged request. + * + * @see {@link paginated} + * @param endpoint - The request endpoint, e.g. /projects. + * @param options - Request queryString options which may also include page variables. + */ + async pagedRequest( endpoint: string, options?: ListOptions, - ): Promise> { - const request = new URL(endpoint); + ): Promise> { + const request = new URL(`${this.config.apiBaseUrl}${endpoint}`); for (const key in options) { if (options[key]) { request.searchParams.append(key, options[key]!.toString()); @@ -80,20 +109,20 @@ export class GitLabClient { } } -export type ListOptions = { - [key: string]: string | number | boolean | undefined; - group?: string; - per_page?: number | undefined; - page?: number | undefined; -}; - -export type PagedResponse = { - items: T[]; - nextPage?: number; -}; - -export async function* paginated( - request: (options: ListOptions) => Promise>, +/** + * Advances through each page and provides each item from a paginated request. + * + * The async generator function yields each item from repeated calls to the + * provided request function. The generator walks through each available page by + * setting the page key in the options passed into the request function and + * making repeated calls until there are no more pages. + * + * @see {@link pagedRequest} + * @param request - Function which returns a PagedResponse to walk through. + * @param options - Initial ListOptions for the request function. + */ +export async function* paginated( + request: (options: ListOptions) => Promise>, options: ListOptions, ) { let res; diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts index 4c6342c6c6..ebad95e72f 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts @@ -56,19 +56,16 @@ export class DefaultCatalogCollator implements DocumentCollator { }); } - constructor({ - discovery, - locationTemplate, - filter, - catalogClient, - tokenManager, - }: { + constructor(options: { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; locationTemplate?: string; filter?: CatalogEntitiesRequest['filter']; catalogClient?: CatalogApi; }) { + const { discovery, locationTemplate, filter, catalogClient, tokenManager } = + options; + this.discovery = discovery; this.locationTemplate = locationTemplate || '/catalog/:namespace/:kind/:name'; diff --git a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts index c9ebc8f723..1618ef8d7b 100644 --- a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts @@ -336,7 +336,10 @@ export class NextCatalogBuilder { const parser = this.parser || defaultEntityDataParser; const dbClient = await database.getClient(); - await applyDatabaseMigrations(dbClient); + if (!database.migrations?.skip) { + logger.info('Performing database migration'); + await applyDatabaseMigrations(dbClient); + } const db = new CommonDatabase(dbClient, logger); diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index c107a4e758..50842898df 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-graph +## 0.2.3 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.2 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 2a44593a4a..b421a15265 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,28 +23,29 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "classnames": "^2.3.1", "lodash": "^4.17.15", "p-limit": "^3.1.0", "qs": "^6.9.4", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 6397718fd7..0fae63ff9d 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-import +## 0.7.5 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.7.4 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index b370c9fa33..d417a337df 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.7.4", + "version": "0.7.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,32 +33,33 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog-react": "^0.6.5", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "@types/react": "*", "git-url-parse": "^11.6.0", "js-base64": "^3.6.0", "lodash": "^4.17.21", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-hook-form": "^7.12.2", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", "yaml": "^1.10.0" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 276b6d351c..6154eec757 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -79,6 +79,9 @@ describe('CatalogImportClient', () => { signOut: () => { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; const scmIntegrationsApi = ScmIntegrations.fromConfig( diff --git a/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx b/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx index 784cbfbe9e..d6132b249e 100644 --- a/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx +++ b/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx @@ -37,6 +37,9 @@ describe('', () => { signOut: () => { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; let apis: TestApiRegistry; diff --git a/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx b/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx index 1778af73dc..498e786eb3 100644 --- a/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx +++ b/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx @@ -43,6 +43,9 @@ describe('', () => { signOut: () => { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; let apis: TestApiRegistry; diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index e6d00b2f8f..c628735ef1 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-react +## 0.6.5 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- 69034b4419: Fix typo in catalog-react package.json +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/core-app-api@0.2.0 + - @backstage/version-bridge@0.1.1 + ## 0.6.4 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index c65f9144e5..b5a6884fa5 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "0.6.4", + "version": "0.6.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -15,7 +15,7 @@ "repository": { "type": "git", "url": "https://github.com/backstage/backstage", - "directory": "plugins/plugin-catalog-common-react" + "directory": "plugins/catalog-react" }, "keywords": [ "backstage" @@ -31,28 +31,30 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-app-api": "^0.1.24", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-app-api": "^0.2.0", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.4", "@backstage/integration": "^0.6.10", "@backstage/types": "^0.1.1", - "@backstage/version-bridge": "^0.1.0", + "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "jwt-decode": "^3.1.0", "lodash": "^4.17.21", "qs": "^6.9.4", - "react": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.22", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 7fda738d32..e0a6dd857a 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog +## 0.7.4 + +### Patch Changes + +- 9603827bb5: Addressed some peer dependency warnings +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.7.3 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 6caadb7b42..57e14b5475 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "0.7.3", + "version": "0.7.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,29 +33,30 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "history": "^5.0.0", "lodash": "^4.17.21", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-helmet": "6.1.0", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/catalog/src/CatalogClientWrapper.test.ts b/plugins/catalog/src/CatalogClientWrapper.test.ts index 0e9da8d8c8..6917b5abed 100644 --- a/plugins/catalog/src/CatalogClientWrapper.test.ts +++ b/plugins/catalog/src/CatalogClientWrapper.test.ts @@ -40,6 +40,9 @@ const identityApi: IdentityApi = { async signOut() { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; const guestIdentityApi: IdentityApi = { getUserId() { @@ -54,6 +57,9 @@ const guestIdentityApi: IdentityApi = { async signOut() { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; describe('CatalogClientWrapper', () => { diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index 3f3fc804e1..a45afe6e02 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -31,9 +31,8 @@ import { renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; -import { fireEvent } from '@testing-library/react'; +import { act, fireEvent } from '@testing-library/react'; import React from 'react'; -import { act } from 'react-dom/test-utils'; import { Route, Routes } from 'react-router'; import { EntityLayout } from './EntityLayout'; diff --git a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx b/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx index 9681420e1c..ad111380f8 100644 --- a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx +++ b/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx @@ -16,8 +16,7 @@ import React from 'react'; import { Tabbed } from './Tabbed'; import { renderInTestApp } from '@backstage/test-utils'; -import { fireEvent } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { act, fireEvent } from '@testing-library/react'; import { Routes, Route } from 'react-router'; describe('Tabbed layout', () => { diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index aa0b5a08a7..8137294300 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-circleci +## 0.2.31 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- 56d04330c4: Switch to using `LogViewer` component from `@backstage/core-components` to display action output. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.30 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 45579ab82b..e2aa415043 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.2.30", + "version": "0.2.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,9 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,25 +44,24 @@ "humanize-duration": "^3.27.0", "lodash": "^4.17.21", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-lazylog": "^4.5.2", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", "@types/humanize-duration": "^3.25.1", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/react-lazylog": "^4.5.0", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx index a4c2af241f..4a4a8a45f2 100644 --- a/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx +++ b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Progress } from '@backstage/core-components'; +import { LogViewer } from '@backstage/core-components'; import { Accordion, AccordionDetails, @@ -24,10 +24,9 @@ import { import { makeStyles } from '@material-ui/core/styles'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { BuildStepAction } from 'circleci-api'; -import React, { Suspense, useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { durationHumanized } from '../../../../util'; -const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); const useStyles = makeStyles({ accordionDetails: { padding: 0, @@ -85,11 +84,9 @@ export const ActionOutput = ({ {messages.length === 0 ? ( 'Nothing here...' ) : ( - }> -
- -
-
+
+ +
)} diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 735f5d2167..04963a6fbb 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cloudbuild +## 0.2.29 + +### Patch Changes + +- c77def982f: Remove unnecessary dependency. +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.28 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 3c9e14c9e7..6e91b22fcb 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.2.28", + "version": "0.2.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,27 +32,27 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "luxon": "^2.0.2", "qs": "^6.9.4", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-lazylog": "^4.5.3", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index b5b413b9d2..777dc6d5df 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-code-coverage +## 0.1.19 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.18 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 907a0abcd7..951a93110a 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.1.18", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,10 +23,10 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -34,18 +34,19 @@ "@material-ui/styles": "^4.11.0", "highlight.js": "^10.6.0", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "recharts": "^1.8.5" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index fc4f8697b8..d4999dc573 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.15 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/config-schema/api-report.md b/plugins/config-schema/api-report.md index efeb1646eb..f3b620738f 100644 --- a/plugins/config-schema/api-report.md +++ b/plugins/config-schema/api-report.md @@ -41,11 +41,9 @@ export const configSchemaPlugin: BackstagePlugin< {} >; -// Warning: (ae-missing-release-tag) "StaticSchemaLoader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export class StaticSchemaLoader implements ConfigSchemaApi { - constructor({ url }?: { url?: string }); + constructor(options?: { url?: string }); // (undocumented) schema$(): Observable; } diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 6b79c5493c..59d34cc00d 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.14", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.5", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -31,16 +31,17 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "jsonschema": "^1.2.6", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/config-schema/src/api/StaticSchemaLoader.ts b/plugins/config-schema/src/api/StaticSchemaLoader.ts index 71eae63376..5fc979b76d 100644 --- a/plugins/config-schema/src/api/StaticSchemaLoader.ts +++ b/plugins/config-schema/src/api/StaticSchemaLoader.ts @@ -24,12 +24,14 @@ const DEFAULT_URL = 'config-schema.json'; /** * A ConfigSchemaApi implementation that loads the configuration from a URL. + * + * @public */ export class StaticSchemaLoader implements ConfigSchemaApi { private readonly url: string; - constructor({ url = DEFAULT_URL }: { url?: string } = {}) { - this.url = url; + constructor(options: { url?: string } = {}) { + this.url = options?.url ?? DEFAULT_URL; } schema$(): Observable { diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index c43d7c0612..183cc27dcf 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cost-insights +## 0.11.13 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.11.12 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 6a2d582d63..45975163e4 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.11.12", + "version": "0.11.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,33 +32,34 @@ }, "dependencies": { "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.9.6", - "@types/react": "*", "@types/recharts": "^1.8.14", "classnames": "^2.2.6", "history": "^5.0.0", "luxon": "^2.0.2", "pluralize": "^8.0.0", "qs": "^6.9.4", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "recharts": "^1.8.5", "regression": "^2.0.1", "yup": "^0.32.9" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/cost-insights/src/testUtils/providers.tsx b/plugins/cost-insights/src/testUtils/providers.tsx index 09d2feb71b..fb18c1a68c 100644 --- a/plugins/cost-insights/src/testUtils/providers.tsx +++ b/plugins/cost-insights/src/testUtils/providers.tsx @@ -187,6 +187,9 @@ export const MockCostInsightsApiProvider = ({ getIdToken: jest.fn(), getUserId: jest.fn(), signOut: jest.fn(), + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; const defaultCostInsightsApi: CostInsightsApi = { diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 0560527f80..0123dcd77a 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-explore-react +## 0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@0.3.0 + ## 0.0.7 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 00e5e87918..ad7f92751e 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.7", + "version": "0.0.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/core-plugin-api": "^0.2.2" + "@backstage/core-plugin-api": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.22", + "@backstage/cli": "^0.10.1", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 73117d7f32..fce849b17d 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-explore +## 0.3.22 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + - @backstage/plugin-explore-react@0.0.8 + ## 0.3.21 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index b4e08a526f..9975992ea5 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.3.21", + "version": "0.3.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,27 +32,28 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", - "@backstage/plugin-explore-react": "^0.0.7", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-explore-react": "^0.0.8", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "classnames": "^2.2.6", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index b137ed1f73..6cb869284e 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-firehydrant +## 0.1.9 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.8 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 2b3bf05b1e..68ee004605 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.1.8", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,23 +22,24 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "luxon": "^1.27.0", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index e0ad30ef69..b63911f5db 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-fossa +## 0.2.24 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.23 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 7d56fdc333..b28c8bd89f 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.23", + "version": "0.2.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,10 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,15 +44,16 @@ "cross-fetch": "^3.0.6", "luxon": "^2.0.2", "p-limit": "^3.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/fossa/src/api/FossaClient.test.ts b/plugins/fossa/src/api/FossaClient.test.ts index 4debb37ad6..e723a4b00a 100644 --- a/plugins/fossa/src/api/FossaClient.test.ts +++ b/plugins/fossa/src/api/FossaClient.test.ts @@ -24,20 +24,11 @@ import { UrlPatternDiscovery } from '@backstage/core-app-api'; const server = setupServer(); -const identityApi: IdentityApi = { - getUserId() { - return 'jane-fonda'; - }, - getProfile() { - return { email: 'jane-fonda@spotify.com' }; - }, +const identityApi = { async getIdToken() { return Promise.resolve('fake-id-token'); }, - async signOut() { - return Promise.resolve(); - }, -}; +} as IdentityApi; describe('FossaClient', () => { setupRequestMockHandlers(server); diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index ac8dd570a6..7d832c5a4b 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gcp-projects +## 0.3.10 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index a3a53b317e..e73dc7736a 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.9", + "version": "0.3.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,22 +31,23 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "^6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 1c627ab086..c4e50a250b 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-git-release-manager +## 0.3.4 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.3.3 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index c5ef82ac16..ab11255e08 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,28 +21,29 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/integration": "^0.6.10", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "@types/react": "*", "luxon": "^2.0.2", "qs": "^6.10.1", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", "recharts": "^1.8.5" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 7992f201cf..4c4a339415 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-github-actions +## 0.4.26 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- cbd20c46f1: Switch to using `LogViewer` component from `@backstage/core-components` to display build logs. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.4.25 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index b0fa469a50..434a0b6224 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.4.25", + "version": "0.4.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,28 +34,28 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-lazylog": "^4.5.3", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx index 399fed9557..0f1670bbbc 100644 --- a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx +++ b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; -import { Progress } from '@backstage/core-components'; +import { LogViewer } from '@backstage/core-components'; import { configApiRef, useApi } from '@backstage/core-plugin-api'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { @@ -32,14 +32,11 @@ import { } from '@material-ui/core'; import DescriptionIcon from '@material-ui/icons/Description'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import React, { Suspense } from 'react'; +import React from 'react'; import { useProjectName } from '../useProjectName'; import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs'; -const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); -const LinePart = React.lazy(() => import('react-lazylog/build/LinePart')); - -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles(theme => ({ button: { order: -1, marginRight: 0, @@ -53,49 +50,19 @@ const useStyles = makeStyles(() => ({ justifyContent: 'center', margin: 'auto', }, - normalLog: { + normalLogContainer: { height: '75vh', width: '100%', }, - modalLog: { + modalLogContainer: { height: '100%', width: '100%', }, + log: { + background: theme.palette.background.default, + }, })); -const DisplayLog = ({ - jobLogs, - className, -}: { - jobLogs: any; - className: string; -}) => { - return ( - }> -
- { - if ( - line.toLocaleLowerCase().includes('error') || - line.toLocaleLowerCase().includes('failed') || - line.toLocaleLowerCase().includes('failure') - ) { - return ( - - ); - } - return line; - }} - /> -
-
- ); -}; - /** * A component for Run Logs visualization. */ @@ -123,6 +90,7 @@ export const WorkflowRunLogs = ({ repo, id: runId, }); + const logText = jobLogs.value ? String(jobLogs.value) : undefined; const [open, setOpen] = React.useState(false); const handleOpen = () => { @@ -162,18 +130,19 @@ export const WorkflowRunLogs = ({ onClose={handleClose} > - +
+ +
- {jobLogs.value && ( - + {logText && ( +
+ +
)} ); diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 701b167135..767fd90780 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-github-deployments +## 0.1.22 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.21 ### Patch Changes diff --git a/plugins/github-deployments/api-report.md b/plugins/github-deployments/api-report.md index a8fca185e5..36680cb020 100644 --- a/plugins/github-deployments/api-report.md +++ b/plugins/github-deployments/api-report.md @@ -38,11 +38,7 @@ function createStatusColumn(): TableColumn; // Warning: (ae-missing-release-tag) "EntityGithubDeploymentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const EntityGithubDeploymentsCard: ({ - last, - lastStatuses, - columns, -}: { +export const EntityGithubDeploymentsCard: (props: { last?: number | undefined; lastStatuses?: number | undefined; columns?: TableColumn[] | undefined; @@ -58,12 +54,9 @@ export const githubDeploymentsPlugin: BackstagePlugin<{}, {}>; // Warning: (ae-missing-release-tag) "GithubDeploymentsTable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function GithubDeploymentsTable({ - deployments, - isLoading, - reload, - columns, -}: GithubDeploymentsTableProps): JSX.Element; +export function GithubDeploymentsTable( + props: GithubDeploymentsTableProps, +): JSX.Element; // @public (undocumented) export namespace GithubDeploymentsTable { @@ -78,7 +71,7 @@ export namespace GithubDeploymentsTable { // Warning: (ae-missing-release-tag) "GithubStateIndicator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const GithubStateIndicator: ({ state }: { state: string }) => JSX.Element; +const GithubStateIndicator: (props: { state: string }) => JSX.Element; // Warning: (ae-missing-release-tag) "isGithubDeploymentsAvailable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index a1dad4ecca..1965f98ef1 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.21", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,27 +22,28 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/graphql": "^4.5.8", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index c01cd98a45..c1c33607a1 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -80,15 +80,12 @@ const GithubDeploymentsComponent = ({ ); }; -export const GithubDeploymentsCard = ({ - last, - lastStatuses, - columns, -}: { +export const GithubDeploymentsCard = (props: { last?: number; lastStatuses?: number; columns?: TableColumn[]; }) => { + const { last, lastStatuses, columns } = props; const { entity } = useEntity(); const [host] = [ entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], diff --git a/plugins/github-deployments/src/components/GithubDeploymentsTable/GithubDeploymentsTable.tsx b/plugins/github-deployments/src/components/GithubDeploymentsTable/GithubDeploymentsTable.tsx index 2de7cdf419..2c48f3eef1 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsTable/GithubDeploymentsTable.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsTable/GithubDeploymentsTable.tsx @@ -36,12 +36,8 @@ type GithubDeploymentsTableProps = { columns: TableColumn[]; }; -export function GithubDeploymentsTable({ - deployments, - isLoading, - reload, - columns, -}: GithubDeploymentsTableProps) { +export function GithubDeploymentsTable(props: GithubDeploymentsTableProps) { + const { deployments, isLoading, reload, columns } = props; const classes = useStyles(); return ( diff --git a/plugins/github-deployments/src/components/GithubDeploymentsTable/columns.tsx b/plugins/github-deployments/src/components/GithubDeploymentsTable/columns.tsx index e892b12427..9a720c0e75 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsTable/columns.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsTable/columns.tsx @@ -27,8 +27,8 @@ import { Link, } from '@backstage/core-components'; -export const GithubStateIndicator = ({ state }: { state: string }) => { - switch (state) { +export const GithubStateIndicator = (props: { state: string }) => { + switch (props.state) { case 'PENDING': return ; case 'IN_PROGRESS': diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 42f3533d31..69ece49c63 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gitops-profiles +## 0.3.10 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 6b211f59ed..834fd2f7cf 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.9", + "version": "0.3.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,22 +32,23 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 4fbf6b0dab..2a013aa6b3 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-graphiql +## 0.2.24 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + +## 0.2.23 + +### Patch Changes + +- dde1681f33: chore(dependencies): bump `graphiql` package to latest + ## 0.2.22 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 49c4d9952c..ec5a37bf36 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.22", + "version": "0.2.24", "private": false, "publishConfig": { "access": "public", @@ -31,23 +31,24 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "graphiql": "^1.0.0-alpha.10", - "graphql": "15.5.0", - "react": "^16.13.1", - "react-dom": "^16.13.1", + "graphiql": "^1.5.12", + "graphql": "^16.0.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx index ae84b549ec..90f8edd4ad 100644 --- a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx +++ b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { GraphiQLPage } from './GraphiQLPage'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; -import { act } from 'react-dom/test-utils'; +import { act } from '@testing-library/react'; import { renderWithEffects, TestApiProvider } from '@backstage/test-utils'; import { GraphQLBrowseApi, graphQlBrowseApiRef } from '../../lib/api'; import { configApiRef } from '@backstage/core-plugin-api'; diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 09e379a625..644d319b70 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-home +## 0.4.7 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.4.6 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 97ec5fdfc2..b04e4a787d 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.6", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,24 +21,25 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "lodash": "^4.17.21", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 1bff4b22ef..a0698bf4a3 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-ilert +## 0.1.18 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.17 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 2e477b2f06..5c07bc9d21 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", @@ -34,15 +34,16 @@ "@material-ui/pickers": "^3.3.10", "humanize-duration": "^3.26.0", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 1daba68a1d..c59c7581af 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-jenkins +## 0.5.14 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.5.13 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index e879d13a88..2211bf54de 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.5.13", + "version": "0.5.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,25 +33,26 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 33ec4bd95a..be4f2d2a29 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kafka +## 0.2.22 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.21 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 41d677aece..309e239a68 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.2.21", + "version": "0.2.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,23 +22,24 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 15a69b3967..ccd7ce7194 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-kubernetes-backend +## 0.4.0 + +### Minor Changes + +- c010632f88: Add pod metrics lookup and display in pod table. + + ## Backwards incompatible changes + + If your Kubernetes distribution does not have the [metrics server](https://github.com/kubernetes-sigs/metrics-server) installed, + you will need to set the `skipMetricsLookup` config flag to `false`. + + See the [configuration docs](https://backstage.io/docs/features/kubernetes/configuration) for more details. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.2.0 + - @backstage/backend-common@0.9.13 + ## 0.3.20 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index c2f4eae4ba..253cdfde18 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.3.20", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,11 +32,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", "@backstage/errors": "^0.1.5", - "@backstage/plugin-kubernetes-common": "^0.1.7", + "@backstage/plugin-kubernetes-common": "^0.2.0", "@google-cloud/container": "^2.2.0", "@kubernetes/client-node": "^0.16.0", "@types/express": "^4.17.6", @@ -55,7 +55,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/aws4": "^1.5.1", "supertest": "^6.1.3", "aws-sdk-mock": "^5.2.1", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index db18c64482..8580e73fa7 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-kubernetes-common +## 0.2.0 + +### Minor Changes + +- c010632f88: Add pod metrics lookup and display in pod table. + + ## Backwards incompatible changes + + If your Kubernetes distribution does not have the [metrics server](https://github.com/kubernetes-sigs/metrics-server) installed, + you will need to set the `skipMetricsLookup` config flag to `false`. + + See the [configuration docs](https://backstage.io/docs/features/kubernetes/configuration) for more details. + ## 0.1.7 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index b3de378021..124e3415a7 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.1.7", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,7 @@ "@kubernetes/client-node": "^0.16.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.10.1" }, "jest": { "roots": [ diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 819709599f..0329a9bc5b 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-kubernetes +## 0.5.0 + +### Minor Changes + +- c010632f88: Add pod metrics lookup and display in pod table. + + ## Backwards incompatible changes + + If your Kubernetes distribution does not have the [metrics server](https://github.com/kubernetes-sigs/metrics-server) installed, + you will need to set the `skipMetricsLookup` config flag to `false`. + + See the [configuration docs](https://backstage.io/docs/features/kubernetes/configuration) for more details. + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-kubernetes-common@0.2.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.4.22 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 5e7a5bdf8d..3a2ea6a9a9 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.4.22", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,10 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", - "@backstage/plugin-kubernetes-common": "^0.1.7", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-kubernetes-common": "^0.2.0", "@kubernetes/client-node": "^0.16.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -46,16 +46,17 @@ "js-yaml": "^4.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 48ef9a178d..f9b5f6a6ea 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-lighthouse +## 0.2.31 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.30 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index cbd5db27b4..43aabc3e3f 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.2.30", + "version": "0.2.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,30 +34,31 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", "@testing-library/user-event": "^13.1.8", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/react": "*", + "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 89b77e9866..3b8ab0dd8a 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-newrelic +## 0.3.10 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 6676547a85..b7be235b9e 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.9", + "version": "0.3.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,21 +32,22 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 37c3320810..0576d644da 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-org +## 0.3.30 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.3.29 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 2adb6c5d18..4e7f556547 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.3.29", + "version": "0.3.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,25 +22,26 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "qs": "^6.10.1", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index bb74598f2a..e0c6ec0f29 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-pagerduty +## 0.3.19 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.3.18 ### Patch Changes diff --git a/plugins/pagerduty/api-report.md b/plugins/pagerduty/api-report.md index 689edae1e0..bd26531da6 100644 --- a/plugins/pagerduty/api-report.md +++ b/plugins/pagerduty/api-report.md @@ -10,7 +10,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { ConfigApi } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { PropsWithChildren } from 'react'; +import { ReactNode } from 'react'; // Warning: (ae-missing-release-tag) "EntityPagerDutyCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -65,12 +65,7 @@ export class PagerDutyClient implements PagerDutyApi { // Warning: (ae-forgotten-export) The symbol "TriggerAlarmRequest" needs to be exported by the entry point index.d.ts // // (undocumented) - triggerAlarm({ - integrationKey, - source, - description, - userName, - }: TriggerAlarmRequest): Promise; + triggerAlarm(request: TriggerAlarmRequest): Promise; } // Warning: (ae-missing-release-tag) "pagerDutyPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -84,9 +79,7 @@ export { pagerDutyPlugin as plugin }; // Warning: (ae-missing-release-tag) "TriggerButton" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function TriggerButton({ - children, -}: PropsWithChildren): JSX.Element; +export function TriggerButton(props: TriggerButtonProps): JSX.Element; // Warning: (ae-missing-release-tag) "UnauthorizedError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 13cb8854ae..59e76878b5 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.3.18", + "version": "0.3.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,26 +32,27 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "classnames": "^2.2.6", "luxon": "2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/pagerduty/src/api/client.ts b/plugins/pagerduty/src/api/client.ts index c006403fe7..65ff83e7ba 100644 --- a/plugins/pagerduty/src/api/client.ts +++ b/plugins/pagerduty/src/api/client.ts @@ -91,12 +91,9 @@ export class PagerDutyClient implements PagerDutyApi { return oncalls; } - triggerAlarm({ - integrationKey, - source, - description, - userName, - }: TriggerAlarmRequest): Promise { + triggerAlarm(request: TriggerAlarmRequest): Promise { + const { integrationKey, source, description, userName } = request; + const body = JSON.stringify({ event_action: 'trigger', routing_key: integrationKey, diff --git a/plugins/pagerduty/src/components/TriggerButton/index.tsx b/plugins/pagerduty/src/components/TriggerButton/index.tsx index 93897c77be..6f83effcf4 100644 --- a/plugins/pagerduty/src/components/TriggerButton/index.tsx +++ b/plugins/pagerduty/src/components/TriggerButton/index.tsx @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useCallback, PropsWithChildren, useState } from 'react'; +import React, { useCallback, ReactNode, useState } from 'react'; import { makeStyles, Button } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import { usePagerdutyEntity } from '../../hooks'; import { TriggerDialog } from '../TriggerDialog'; -export type TriggerButtonProps = {}; +export type TriggerButtonProps = { + children?: ReactNode; +}; const useStyles = makeStyles(theme => ({ buttonStyle: { @@ -32,9 +34,7 @@ const useStyles = makeStyles(theme => ({ }, })); -export function TriggerButton({ - children, -}: PropsWithChildren) { +export function TriggerButton(props: TriggerButtonProps) { const { buttonStyle } = useStyles(); const { integrationKey } = usePagerdutyEntity(); const [dialogShown, setDialogShown] = useState(false); @@ -56,7 +56,7 @@ export function TriggerButton({ disabled={disabled} > {integrationKey - ? children ?? 'Create Incident' + ? props.children ?? 'Create Incident' : 'Missing integration key'} {integrationKey && ( diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 28df6bccbc..cca070ae0c 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.2.1 + +### Patch Changes + +- a036b65c2f: Updated to use the new `BackstageIdentityResponse` type from `@backstage/plugin-auth-backend`. + + The `BackstageIdentityResponse` type is backwards compatible with the `BackstageIdentity`, and provides an additional `identity` field with the claims of the user. + +- Updated dependencies + - @backstage/plugin-auth-backend@0.5.0 + - @backstage/backend-common@0.9.13 + - @backstage/plugin-permission-node@0.2.1 + ## 0.2.0 ### Minor Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 2018439398..ed3bd86636 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.2.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,11 +19,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/config": "^0.1.11", - "@backstage/plugin-auth-backend": "^0.4.10", + "@backstage/plugin-auth-backend": "^0.5.0", "@backstage/plugin-permission-common": "^0.2.0", - "@backstage/plugin-permission-node": "^0.2.0", + "@backstage/plugin-permission-node": "^0.2.1", "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -33,7 +33,7 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "msw": "^0.35.0" diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index b85e7feb85..41791b8fc8 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -23,7 +23,7 @@ import { PluginEndpointDiscovery, } from '@backstage/backend-common'; import { - BackstageIdentity, + BackstageIdentityResponse, IdentityClient, } from '@backstage/plugin-auth-backend'; import { @@ -71,7 +71,7 @@ export interface RouterOptions { const handleRequest = async ( { id, resourceRef, ...request }: Identified, - user: BackstageIdentity | undefined, + user: BackstageIdentityResponse | undefined, policy: PermissionPolicy, permissionIntegrationClient: PermissionIntegrationClient, authHeader?: string, diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 64af0e353b..3fdf0ccfff 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.2.1 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- a036b65c2f: Updated to use the new `BackstageIdentityResponse` type from `@backstage/plugin-auth-backend`. + + The `BackstageIdentityResponse` type is backwards compatible with the `BackstageIdentity`, and provides an additional `identity` field with the claims of the user. + +- Updated dependencies + - @backstage/plugin-auth-backend@0.5.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index 75c45a9250..3df1386d4d 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -5,7 +5,7 @@ ```ts import { AuthorizeRequest } from '@backstage/plugin-permission-common'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; -import { BackstageIdentity } from '@backstage/plugin-auth-backend'; +import { BackstageIdentityResponse } from '@backstage/plugin-auth-backend'; import { PermissionCondition } from '@backstage/plugin-permission-common'; import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { Router } from 'express'; @@ -83,11 +83,7 @@ export const createConditionTransformer: < ) => ConditionTransformer; // @public -export const createPermissionIntegrationRouter: ({ - resourceType, - rules, - getResource, -}: { +export const createPermissionIntegrationRouter: (options: { resourceType: string; rules: PermissionRule[]; getResource: (resourceRef: string) => Promise; @@ -98,7 +94,7 @@ export interface PermissionPolicy { // (undocumented) handle( request: PolicyAuthorizeRequest, - user?: BackstageIdentity, + user?: BackstageIdentityResponse, ): Promise; } diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 1a3d3688d1..5e0a300873 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.2.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,14 +29,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/plugin-auth-backend": "^0.4.10", + "@backstage/plugin-auth-backend": "^0.5.0", "@backstage/plugin-permission-common": "^0.2.0", "@types/express": "^4.17.6", "express": "^4.17.1", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 70b72fef7e..b8d3e02a81 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -116,17 +116,15 @@ const applyConditions = ( * This is used to construct the `createPermissionIntegrationRouter`, a function to add an * authorization route to your backend plugin. This route will be called by the `permission-backend` * when authorization conditions relating to this plugin need to be evaluated. + * * @public */ -export const createPermissionIntegrationRouter = ({ - resourceType, - rules, - getResource, -}: { +export const createPermissionIntegrationRouter = (options: { resourceType: string; rules: PermissionRule[]; getResource: (resourceRef: string) => Promise; }): Router => { + const { resourceType, rules, getResource } = options; const router = Router(); const getRule = createGetRule(rules); diff --git a/plugins/permission-node/src/policy/types.ts b/plugins/permission-node/src/policy/types.ts index 3548d051f6..d122ad8d8d 100644 --- a/plugins/permission-node/src/policy/types.ts +++ b/plugins/permission-node/src/policy/types.ts @@ -20,7 +20,7 @@ import { PermissionCondition, PermissionCriteria, } from '@backstage/plugin-permission-common'; -import { BackstageIdentity } from '@backstage/plugin-auth-backend'; +import { BackstageIdentityResponse } from '@backstage/plugin-auth-backend'; /** * An authorization request to be evaluated by the {@link PermissionPolicy}. @@ -83,6 +83,6 @@ export type PolicyDecision = export interface PermissionPolicy { handle( request: PolicyAuthorizeRequest, - user?: BackstageIdentity, + user?: BackstageIdentityResponse, ): Promise; } diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 9592985354..44c5a326d6 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.1.1 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-plugin-api@0.3.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/permission-react/api-report.md b/plugins/permission-react/api-report.md index 65f93de8a0..c10317495a 100644 --- a/plugins/permission-react/api-report.md +++ b/plugins/permission-react/api-report.md @@ -6,12 +6,13 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { AuthorizeRequest } from '@backstage/plugin-permission-common'; import { AuthorizeResponse } from '@backstage/plugin-permission-common'; +import { ComponentProps } from 'react'; import { Config } from '@backstage/config'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; import { Permission } from '@backstage/plugin-permission-common'; -import { default as React_2 } from 'react'; -import { RouteProps } from 'react-router'; +import { ReactElement } from 'react'; +import { Route } from 'react-router'; // @public (undocumented) export type AsyncPermissionResult = { @@ -25,11 +26,7 @@ export class IdentityPermissionApi implements PermissionApi { // (undocumented) authorize(request: AuthorizeRequest): Promise; // (undocumented) - static create({ - configApi, - discoveryApi, - identityApi, - }: { + static create(options: { configApi: Config; discoveryApi: DiscoveryApi; identityApi: IdentityApi; @@ -45,19 +42,13 @@ export type PermissionApi = { export const permissionApiRef: ApiRef; // @public -export const PermissionedRoute: ({ - permission, - resourceRef, - errorComponent, - ...props -}: RouteProps & { - permission: Permission; - resourceRef?: string | undefined; - errorComponent?: - | React_2.ReactElement> - | null - | undefined; -}) => JSX.Element; +export const PermissionedRoute: ( + props: ComponentProps & { + permission: Permission; + resourceRef?: string; + errorComponent?: ReactElement | null; + }, +) => JSX.Element; // @public export const usePermission: ( diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 26c5f71da0..7f49c5eb73 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.1.0", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,17 +28,19 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/plugin-permission-common": "^0.2.0", - "@types/react": "*", "cross-fetch": "^3.0.6", - "react": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.22", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.7" diff --git a/plugins/permission-react/src/apis/IdentityPermissionApi.ts b/plugins/permission-react/src/apis/IdentityPermissionApi.ts index a68060a61d..19de564f84 100644 --- a/plugins/permission-react/src/apis/IdentityPermissionApi.ts +++ b/plugins/permission-react/src/apis/IdentityPermissionApi.ts @@ -34,15 +34,12 @@ export class IdentityPermissionApi implements PermissionApi { private readonly identityApi: IdentityApi, ) {} - static create({ - configApi, - discoveryApi, - identityApi, - }: { + static create(options: { configApi: Config; discoveryApi: DiscoveryApi; identityApi: IdentityApi; }) { + const { configApi, discoveryApi, identityApi } = options; const permissionClient = new PermissionClient({ discoveryApi, configApi }); return new IdentityPermissionApi(permissionClient, identityApi); } diff --git a/plugins/permission-react/src/components/PermissionedRoute.tsx b/plugins/permission-react/src/components/PermissionedRoute.tsx index 1a3668205b..76017308aa 100644 --- a/plugins/permission-react/src/components/PermissionedRoute.tsx +++ b/plugins/permission-react/src/components/PermissionedRoute.tsx @@ -21,20 +21,19 @@ import { usePermission } from '../hooks'; import { Permission } from '@backstage/plugin-permission-common'; /** - * Returns a React Router Route which only renders the element when authorized. If unathorized, the Route will render a + * Returns a React Router Route which only renders the element when authorized. If unauthorized, the Route will render a * NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}). + * * @public */ -export const PermissionedRoute = ({ - permission, - resourceRef, - errorComponent, - ...props -}: ComponentProps & { - permission: Permission; - resourceRef?: string; - errorComponent?: ReactElement | null; -}) => { +export const PermissionedRoute = ( + props: ComponentProps & { + permission: Permission; + resourceRef?: string; + errorComponent?: ReactElement | null; + }, +) => { + const { permission, resourceRef, errorComponent, ...otherProps } = props; const permissionResult = usePermission(permission, resourceRef); const app = useApp(); const { NotFoundErrorPage } = app.getComponents(); @@ -48,5 +47,5 @@ export const PermissionedRoute = ({ shownElement = props.element; } - return ; + return ; }; diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index aee0a74525..8368deee5e 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-rollbar +## 0.3.20 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.3.19 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index d71c5e1cfe..d6a14a5b2a 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.3.19", + "version": "0.3.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,33 +33,34 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "lodash": "^4.17.21", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-sparklines": "^1.7.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", "@testing-library/user-event": "^13.1.8", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/react": "*", + "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 9dcd6bcb88..5893faedbb 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.2.0 + +### Minor Changes + +- 64db0efffe: update publish format from ESM to CJS + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@0.15.16 + - @backstage/backend-common@0.9.13 + ## 0.1.7 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index cac3d7ea9b..28dc5f7ba6 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,19 +1,19 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.1.7", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": false, "publishConfig": { "access": "public", - "main": "dist/index.esm.js", + "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", + "build": "backstage-cli backend:build", + "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", "prepack": "backstage-cli prepack", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", - "@backstage/plugin-scaffolder-backend": "^0.15.15", + "@backstage/backend-common": "^0.9.13", + "@backstage/plugin-scaffolder-backend": "^0.15.16", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.4", "@backstage/integration": "^0.6.10", @@ -31,7 +31,7 @@ "fs-extra": "^9.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", "@types/command-exists": "^1.2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 3b0add9cd6..3986961f16 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend +## 0.15.16 + +### Patch Changes + +- 2a3fb13718: Bump esbuild to ^0.14.1 +- Updated dependencies + - @backstage/backend-common@0.9.13 + - @backstage/plugin-catalog-backend@0.19.1 + ## 0.15.15 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index bbe59d6458..2dae658d74 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "0.15.15", + "version": "0.15.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,13 +31,13 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-backend": "^0.19.0", + "@backstage/plugin-catalog-backend": "^0.19.1", "@backstage/plugin-scaffolder-common": "^0.1.1", "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.5", "@backstage/types": "^0.1.1", @@ -73,8 +73,8 @@ "vm2": "^3.9.5" }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index b445ec873c..55ccd3e737 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder +## 0.11.14 + +### Patch Changes + +- 6845cce533: Can specify allowedOwners to the RepoUrlPicker picker in a template definition +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- 2edcf7738f: Fix bug with setting owner in RepoUrlPicker causing validation failure +- b291c3176e: Switch to using `LogViewer` component from `@backstage/core-components` to display scaffolder logs. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.11.13 ### Patch Changes diff --git a/plugins/scaffolder/dev/index.tsx b/plugins/scaffolder/dev/index.tsx index 3a749792f1..f7c6aa62fc 100644 --- a/plugins/scaffolder/dev/index.tsx +++ b/plugins/scaffolder/dev/index.tsx @@ -17,7 +17,11 @@ import { CatalogClient } from '@backstage/catalog-client'; import { createDevApp } from '@backstage/dev-utils'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; -import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { + catalogApiRef, + starredEntitiesApiRef, + DefaultStarredEntitiesApi, +} from '@backstage/plugin-catalog-react'; import React from 'react'; import { scaffolderApiRef, ScaffolderClient } from '../src'; import { ScaffolderPage } from '../src/plugin'; @@ -25,14 +29,25 @@ import { configApiRef, discoveryApiRef, identityApiRef, + storageApiRef, } from '@backstage/core-plugin-api'; +import { CatalogEntityPage } from '@backstage/plugin-catalog'; createDevApp() + .addPage({ + path: '/catalog/:kind/:namespace/:name', + element: , + }) .registerApi({ api: catalogApiRef, deps: { discoveryApi: discoveryApiRef }, factory: ({ discoveryApi }) => new CatalogClient({ discoveryApi }), }) + .registerApi({ + api: starredEntitiesApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), + }) .registerApi({ api: scaffolderApiRef, deps: { diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 404bfcd387..e3aaa722b0 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "0.11.13", + "version": "0.11.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,12 +34,12 @@ "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -47,7 +47,6 @@ "@material-ui/lab": "4.0.0-alpha.57", "@rjsf/core": "^3.2.1", "@rjsf/material-ui": "^3.2.1", - "@types/react": "*", "classnames": "^2.2.6", "git-url-parse": "^11.6.0", "humanize-duration": "^3.25.1", @@ -56,20 +55,22 @@ "lodash": "^4.17.21", "luxon": "^2.0.2", "qs": "^6.9.4", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-lazylog": "^4.5.2", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", "use-immer": "^0.6.0", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index 11d12282d2..58ec3dfc02 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -20,7 +20,7 @@ import { Header, Lifecycle, Page, - Progress, + LogViewer, } from '@backstage/core-components'; import { BackstageTheme } from '@backstage/theme'; import { @@ -40,15 +40,13 @@ import Check from '@material-ui/icons/Check'; import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'; import classNames from 'classnames'; import { DateTime, Interval } from 'luxon'; -import React, { memo, Suspense, useEffect, useMemo, useState } from 'react'; +import React, { memo, useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router'; import { useInterval } from 'react-use'; import { Status, TaskOutput } from '../../types'; import { useTaskEventStream } from '../hooks/useEventStream'; import { TaskPageLinks } from './TaskPageLinks'; -const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); - // typings are wrong for this library, so fallback to not parsing types. const humanizeDuration = require('humanize-duration'); @@ -213,22 +211,6 @@ export const TaskStatusStepper = memo( }, ); -const TaskLogger = memo(({ log }: { log: string }) => { - return ( - }> -
- -
-
- ); -}); - const hasLinks = ({ entityRef, remoteUrl, links = [] }: TaskOutput): boolean => !!(entityRef || remoteUrl || links.length > 0); @@ -318,7 +300,9 @@ export const TaskPage = () => { - +
+ +
diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index 60e9ee8840..7ca65fff25 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -20,9 +20,8 @@ import { } from '@backstage/test-utils'; import { lightTheme } from '@backstage/theme'; import { ThemeProvider } from '@material-ui/core'; -import { fireEvent, within } from '@testing-library/react'; +import { act, fireEvent, within } from '@testing-library/react'; import React from 'react'; -import { act } from 'react-dom/test-utils'; import { MemoryRouter, Route } from 'react-router'; import { ScaffolderApi, scaffolderApiRef } from '../../api'; import { rootRouteRef } from '../../routes'; diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 6bd39200c0..f36078c503 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 0.0.6 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly + ## 0.0.5 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/api-report.md b/plugins/search-backend-module-elasticsearch/api-report.md index da1f7d4804..1e798119c3 100644 --- a/plugins/search-backend-module-elasticsearch/api-report.md +++ b/plugins/search-backend-module-elasticsearch/api-report.md @@ -11,8 +11,6 @@ import { SearchEngine } from '@backstage/search-common'; import { SearchQuery } from '@backstage/search-common'; import { SearchResultSet } from '@backstage/search-common'; -// Warning: (ae-missing-release-tag) "ElasticSearchSearchEngine" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export class ElasticSearchSearchEngine implements SearchEngine { constructor( @@ -24,12 +22,9 @@ export class ElasticSearchSearchEngine implements SearchEngine { // Warning: (ae-forgotten-export) The symbol "ElasticSearchOptions" needs to be exported by the entry point index.d.ts // // (undocumented) - static fromConfig({ - logger, - config, - aliasPostfix, - indexPrefix, - }: ElasticSearchOptions): Promise; + static fromConfig( + options: ElasticSearchOptions, + ): Promise; // (undocumented) index(type: string, documents: IndexableDocument[]): Promise; // (undocumented) @@ -41,11 +36,6 @@ export class ElasticSearchSearchEngine implements SearchEngine { // Warning: (ae-forgotten-export) The symbol "ConcreteElasticSearchQuery" needs to be exported by the entry point index.d.ts // // (undocumented) - protected translator({ - term, - filters, - types, - pageCursor, - }: SearchQuery): ConcreteElasticSearchQuery; + protected translator(query: SearchQuery): ConcreteElasticSearchQuery; } ``` diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 1473af7f69..633af83ca6 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "0.0.5", + "version": "0.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.9.12", - "@backstage/cli": "^0.10.0", + "@backstage/backend-common": "^0.9.13", + "@backstage/cli": "^0.10.1", "@elastic/elasticsearch-mock": "^0.3.0" }, "files": [ diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 1a41099c9c..7912c691b3 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -64,6 +64,9 @@ function isBlank(str: string) { return (isEmpty(str) && !isNumber(str)) || nan(str); } +/** + * @public + */ export class ElasticSearchSearchEngine implements SearchEngine { constructor( private readonly elasticSearchClient: Client, @@ -72,12 +75,14 @@ export class ElasticSearchSearchEngine implements SearchEngine { private readonly logger: Logger, ) {} - static async fromConfig({ - logger, - config, - aliasPostfix = `search`, - indexPrefix = ``, - }: ElasticSearchOptions) { + static async fromConfig(options: ElasticSearchOptions) { + const { + logger, + config, + aliasPostfix = `search`, + indexPrefix = ``, + } = options; + return new ElasticSearchSearchEngine( await ElasticSearchSearchEngine.constructElasticSearchClient( logger, @@ -164,12 +169,9 @@ export class ElasticSearchSearchEngine implements SearchEngine { }); } - protected translator({ - term, - filters = {}, - types, - pageCursor, - }: SearchQuery): ConcreteElasticSearchQuery { + protected translator(query: SearchQuery): ConcreteElasticSearchQuery { + const { term, filters = {}, types, pageCursor } = query; + const filter = Object.entries(filters) .filter(([_, value]) => Boolean(value)) .map(([key, value]: [key: string, value: any]) => { @@ -190,7 +192,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { 'Failed to add filters to query. Unrecognized filter type', ); }); - const query = isBlank(term) + const esbQuery = isBlank(term) ? esb.matchAllQuery() : esb .multiMatchQuery(['*'], term) @@ -202,7 +204,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { return { elasticSearchQuery: esb .requestBodySearch() - .query(esb.boolQuery().filter(filter).must([query])) + .query(esb.boolQuery().filter(filter).must([esbQuery])) .from(page * pageSize) .size(pageSize) .toJSON(), diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index daba328467..84851ee352 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-backend-module-pg +## 0.2.2 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.2.1 ### Patch Changes diff --git a/plugins/search-backend-module-pg/api-report.md b/plugins/search-backend-module-pg/api-report.md index 7a171127a3..e2edfc291a 100644 --- a/plugins/search-backend-module-pg/api-report.md +++ b/plugins/search-backend-module-pg/api-report.md @@ -77,9 +77,7 @@ export interface DatabaseStore { export class PgSearchEngine implements SearchEngine { constructor(databaseStore: DatabaseStore); // (undocumented) - static from({ - database, - }: { + static from(options: { database: PluginDatabaseManager; }): Promise; // (undocumented) diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 17edbbf73f..b0b910a5e7 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/search-common": "^0.2.0", "@backstage/plugin-search-backend-node": "^0.4.2", "lodash": "^4.17.21", @@ -28,7 +28,7 @@ }, "devDependencies": { "@backstage/backend-test-utils": "^0.1.10", - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.10.1" }, "files": [ "dist", diff --git a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts index a032dd783e..6fd6c571a8 100644 --- a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts +++ b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts @@ -35,13 +35,11 @@ export type ConcretePgSearchQuery = { export class PgSearchEngine implements SearchEngine { constructor(private readonly databaseStore: DatabaseStore) {} - static async from({ - database, - }: { + static async from(options: { database: PluginDatabaseManager; }): Promise { return new PgSearchEngine( - await DatabaseDocumentStore.create(await database.getClient()), + await DatabaseDocumentStore.create(await options.database.getClient()), ); } diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index bf0c2df174..5b23d0c670 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-backend +## 0.2.8 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.2.7 ### Patch Changes diff --git a/plugins/search-backend/api-report.md b/plugins/search-backend/api-report.md index f2479610fe..cac97bd725 100644 --- a/plugins/search-backend/api-report.md +++ b/plugins/search-backend/api-report.md @@ -7,12 +7,16 @@ import express from 'express'; import { Logger as Logger_2 } from 'winston'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; -// Warning: (ae-forgotten-export) The symbol "RouterOptions" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createRouter({ - engine, - logger, -}: RouterOptions): Promise; +export function createRouter(options: RouterOptions): Promise; + +// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type RouterOptions = { + engine: SearchEngine; + logger: Logger_2; +}; ``` diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 80ca1efa07..1c749cbef4 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "0.2.7", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/search-common": "^0.2.0", "@backstage/plugin-search-backend-node": "^0.4.2", "@types/express": "^4.17.6", @@ -30,7 +30,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index 6df39ca1eb..5bd99988a7 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -20,15 +20,15 @@ import { Logger } from 'winston'; import { SearchQuery, SearchResultSet } from '@backstage/search-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; -type RouterOptions = { +export type RouterOptions = { engine: SearchEngine; logger: Logger; }; -export async function createRouter({ - engine, - logger, -}: RouterOptions): Promise { +export async function createRouter( + options: RouterOptions, +): Promise { + const { engine, logger } = options; const router = Router(); router.get( '/query', diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index a56ff39860..3cfb9093a8 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search +## 0.5.1 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- 382e3a94b3: Export SearchApi interface from plugin +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.5.0 ### Minor Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 1804a7aca8..dbef8e5608 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "0.5.0", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,29 +32,30 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/search-common": "^0.2.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/react": "*", "qs": "^6.9.4", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/search/src/apis.test.ts b/plugins/search/src/apis.test.ts index 91395d1f0b..5721812059 100644 --- a/plugins/search/src/apis.test.ts +++ b/plugins/search/src/apis.test.ts @@ -34,6 +34,9 @@ describe('apis', () => { getUserId: jest.fn(), getProfile: jest.fn(), signOut: jest.fn(), + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }); const client = new SearchClient({ diff --git a/plugins/search/src/components/util.test.tsx b/plugins/search/src/components/util.test.tsx index a5b82370e3..1b452a205e 100644 --- a/plugins/search/src/components/util.test.tsx +++ b/plugins/search/src/components/util.test.tsx @@ -16,11 +16,10 @@ import React from 'react'; import { wrapInTestApp } from '@backstage/test-utils'; -import { render } from '@testing-library/react'; +import { act, render } from '@testing-library/react'; import { useNavigateToQuery } from './util'; import { Routes, Route } from 'react-router-dom'; import { rootRouteRef } from '../plugin'; -import { act } from 'react-dom/test-utils'; const navigate = jest.fn(); jest.mock('react-router-dom', () => ({ diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index cad08289ed..37bb975828 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-sentry +## 0.3.30 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.3.29 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index bb99225479..41dc522e77 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.3.29", + "version": "0.3.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,32 +33,33 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-sparklines": "^1.7.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", "@types/jest": "^26.0.7", "@types/luxon": "^2.0.4", "@types/node": "^14.14.32", - "@types/react": "*", + "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index fdd9f44231..7b9e21571f 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-shortcuts +## 0.1.15 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index f1f41854ef..a706d43e0e 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.1.14", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,27 +21,28 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@types/zen-observable": "^0.8.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-hook-form": "^7.12.2", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", "uuid": "^8.3.2", "zen-observable": "^0.8.15" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 4cfc821482..11f78bc99b 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-sonarqube +## 0.2.9 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.2.8 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 36c903701f..451ec86659 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.2.8", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,15 +44,16 @@ "@material-ui/styles": "^4.10.0", "cross-fetch": "^3.0.6", "rc-progress": "^3.0.0", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/sonarqube/src/api/SonarQubeClient.test.ts b/plugins/sonarqube/src/api/SonarQubeClient.test.ts index f8fd7c2264..a3a301d77a 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.test.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.test.ts @@ -37,6 +37,9 @@ const identityApiAuthenticated: IdentityApi = { async signOut() { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; const identityApiGuest: IdentityApi = { getUserId() { @@ -51,6 +54,9 @@ const identityApiGuest: IdentityApi = { async signOut() { return Promise.resolve(); }, + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; describe('SonarQubeClient', () => { diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index b6d77a50cc..bf7632ce5a 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-splunk-on-call +## 0.3.16 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.3.15 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 28ce356d9c..e5b55836a4 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.3.15", + "version": "0.3.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,25 +32,26 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "classnames": "^2.2.6", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index d0c5e4fcdc..b05b3bf1a3 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-tech-insights +## 0.1.1 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.0 ### Minor Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index a55a0ce904..16e1ec6784 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.1.0", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,27 +20,28 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4", "react-router-dom": "6.0.0-beta.0", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/plugin-tech-insights-common": "^0.2.0", "@backstage/catalog-model": "^0.9.7", "@backstage/errors": "^0.1.4", "@backstage/types": "^0.1.1" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index cef7885007..79f77679e3 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-tech-radar +## 0.4.13 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index d377318e4b..7d6fdb4afe 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.4.12", + "version": "0.4.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,15 +40,16 @@ "color": "^4.0.1", "d3-force": "^2.0.1", "prop-types": "^15.7.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", @@ -56,7 +57,7 @@ "@types/d3-force": "^2.1.1", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/react": "*", + "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/plugins/tech-radar/src/components/RadarComponent.test.tsx b/plugins/tech-radar/src/components/RadarComponent.test.tsx index 2b237c8d83..aeced1a2da 100644 --- a/plugins/tech-radar/src/components/RadarComponent.test.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.test.tsx @@ -15,10 +15,9 @@ */ import React from 'react'; -import { render, waitForElement } from '@testing-library/react'; +import { act, render, waitForElement } from '@testing-library/react'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; -import { act } from 'react-dom/test-utils'; import { TestApiProvider, withLogCollector } from '@backstage/test-utils'; import GetBBoxPolyfill from '../utils/polyfills/getBBox'; diff --git a/plugins/tech-radar/src/components/RadarPage.test.tsx b/plugins/tech-radar/src/components/RadarPage.test.tsx index 7f4e69e388..e9bcb3d314 100644 --- a/plugins/tech-radar/src/components/RadarPage.test.tsx +++ b/plugins/tech-radar/src/components/RadarPage.test.tsx @@ -22,9 +22,8 @@ import { } from '@backstage/test-utils'; import { lightTheme } from '@backstage/theme'; import { ThemeProvider } from '@material-ui/core'; -import { render, waitForElement } from '@testing-library/react'; +import { act, render, waitForElement } from '@testing-library/react'; import React from 'react'; -import { act } from 'react-dom/test-utils'; import GetBBoxPolyfill from '../utils/polyfills/getBBox'; import { RadarPage } from './RadarPage'; import { TechRadarLoaderResponse, techRadarApiRef, TechRadarApi } from '../api'; diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 099049a896..1c3c561bc9 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-backend +## 0.12.0 + +### Minor Changes + +- 1bada775a9: Added the ability for the TechDocs Backend to (optionally) leverage a cache + store to improve performance when reading files from a cloud storage provider. + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/backend-common@0.9.13 + - @backstage/techdocs-common@0.11.0 + ## 0.11.0 ### Minor Changes diff --git a/plugins/techdocs-backend/api-report.md b/plugins/techdocs-backend/api-report.md index 9736555687..b241917bc0 100644 --- a/plugins/techdocs-backend/api-report.md +++ b/plugins/techdocs-backend/api-report.md @@ -28,15 +28,7 @@ export function createRouter(options: RouterOptions): Promise; // @public (undocumented) export class DefaultTechDocsCollator implements DocumentCollator { // @deprecated - constructor({ - discovery, - locationTemplate, - logger, - catalogClient, - tokenManager, - parallelismLimit, - legacyPathCasing, - }: TechDocsCollatorOptions); + constructor(options: TechDocsCollatorOptions); // (undocumented) protected applyArgsToFormat( format: string, diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index b2e7fee261..da1d53e86f 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "0.11.0", + "version": "0.12.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,14 +31,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", "@backstage/search-common": "^0.2.1", - "@backstage/techdocs-common": "^0.10.8", + "@backstage/techdocs-common": "^0.11.0", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", "dockerode": "^3.3.1", @@ -52,8 +52,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/test-utils": "^0.1.24", "@types/dockerode": "^3.3.0", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts index 283d0264e4..fa8a1156fe 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts @@ -63,24 +63,17 @@ export class DefaultTechDocsCollator implements DocumentCollator { /** * @deprecated use static fromConfig method instead. */ - constructor({ - discovery, - locationTemplate, - logger, - catalogClient, - tokenManager, - parallelismLimit = 10, - legacyPathCasing = false, - }: TechDocsCollatorOptions) { - this.discovery = discovery; + constructor(options: TechDocsCollatorOptions) { + this.discovery = options.discovery; this.locationTemplate = - locationTemplate || '/docs/:namespace/:kind/:name/:path'; - this.logger = logger; + options.locationTemplate || '/docs/:namespace/:kind/:name/:path'; + this.logger = options.logger; this.catalogClient = - catalogClient || new CatalogClient({ discoveryApi: discovery }); - this.parallelismLimit = parallelismLimit; - this.legacyPathCasing = legacyPathCasing; - this.tokenManager = tokenManager; + options.catalogClient || + new CatalogClient({ discoveryApi: options.discovery }); + this.parallelismLimit = options.parallelismLimit ?? 10; + this.legacyPathCasing = options.legacyPathCasing ?? false; + this.tokenManager = options.tokenManager; } static fromConfig(config: Config, options: TechDocsCollatorOptions) { diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 22501e0ad7..5cab32a73f 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs +## 0.12.9 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- d90dad84b0: Switch to using `LogViewer` component from `@backstage/core-components` to display build logs. +- 3421826ca8: The problem of lowercase entity triplets which causes docs to not load on entity page is fixed. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog@0.7.4 + - @backstage/integration-react@0.1.15 + - @backstage/plugin-catalog-react@0.6.5 + - @backstage/plugin-search@0.5.1 + ## 0.12.8 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c65fba7210..4ac62a2b56 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "0.12.8", + "version": "0.12.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,37 +34,38 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.14", - "@backstage/plugin-catalog": "^0.7.3", - "@backstage/plugin-catalog-react": "^0.6.4", - "@backstage/plugin-search": "^0.5.0", + "@backstage/integration-react": "^0.1.15", + "@backstage/plugin-catalog": "^0.7.4", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-search": "^0.5.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.10.0", - "@types/react": "*", "dompurify": "^2.2.9", "event-source-polyfill": "^1.0.25", "git-url-parse": "^11.6.0", "lodash": "^4.17.21", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-lazylog": "^4.5.2", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-text-truncate": "^0.16.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/techdocs/src/EntityPageDocs.tsx b/plugins/techdocs/src/EntityPageDocs.tsx index c5356289f0..b10fba6d2e 100644 --- a/plugins/techdocs/src/EntityPageDocs.tsx +++ b/plugins/techdocs/src/EntityPageDocs.tsx @@ -17,15 +17,18 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; import { Reader } from './reader'; +import { toLowerMaybe } from './helpers'; +import { configApiRef, useApi } from '@backstage/core-plugin-api'; export const EntityPageDocs = ({ entity }: { entity: Entity }) => { + const config = useApi(configApiRef); return ( ); diff --git a/plugins/techdocs/src/client.test.ts b/plugins/techdocs/src/client.test.ts index 7624f250d9..bdb2f74772 100644 --- a/plugins/techdocs/src/client.test.ts +++ b/plugins/techdocs/src/client.test.ts @@ -44,6 +44,9 @@ describe('TechDocsStorageClient', () => { getProfile: jest.fn(), getUserId: jest.fn(), signOut: jest.fn(), + getProfileInfo: jest.fn(), + getBackstageIdentity: jest.fn(), + getCredentials: jest.fn(), }; beforeEach(() => { diff --git a/plugins/techdocs/src/helpers.ts b/plugins/techdocs/src/helpers.ts new file mode 100644 index 0000000000..7ff4dec6e7 --- /dev/null +++ b/plugins/techdocs/src/helpers.ts @@ -0,0 +1,26 @@ +/* + * 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 { Config } from '@backstage/config'; + +// Lower-case entity triplets by default, but allow override. +export function toLowerMaybe(str: string, config: Config) { + return config.getOptionalBoolean( + 'techdocs.legacyUseCaseSensitiveTripletPaths', + ) + ? str + : str.toLocaleLowerCase('en-US'); +} diff --git a/plugins/techdocs/src/home/components/DocsCardGrid.tsx b/plugins/techdocs/src/home/components/DocsCardGrid.tsx index 77e69995ae..1aef793bd2 100644 --- a/plugins/techdocs/src/home/components/DocsCardGrid.tsx +++ b/plugins/techdocs/src/home/components/DocsCardGrid.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { useApi, useRouteRef, configApiRef } from '@backstage/core-plugin-api'; import { Card, CardActions, CardContent, CardMedia } from '@material-ui/core'; import { rootDocsRouteRef } from '../../routes'; @@ -26,6 +26,7 @@ import { ItemCardGrid, ItemCardHeader, } from '@backstage/core-components'; +import { toLowerMaybe } from '../../helpers'; export const DocsCardGrid = ({ entities, @@ -33,14 +34,7 @@ export const DocsCardGrid = ({ entities: Entity[] | undefined; }) => { const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef); - - // Lower-case entity triplets by default, but allow override. - const toLowerMaybe = useApi(configApiRef).getOptionalBoolean( - 'techdocs.legacyUseCaseSensitiveTripletPaths', - ) - ? (str: string) => str - : (str: string) => str.toLocaleLowerCase('en-US'); - + const config = useApi(configApiRef); if (!entities) return null; return ( @@ -59,9 +53,10 @@ export const DocsCardGrid = ({ to={getRouteToReaderPageFor({ namespace: toLowerMaybe( entity.metadata.namespace ?? 'default', + config, ), - kind: toLowerMaybe(entity.kind), - name: toLowerMaybe(entity.metadata.name), + kind: toLowerMaybe(entity.kind, config), + name: toLowerMaybe(entity.metadata.name, config), })} color="primary" data-testid="read_docs" diff --git a/plugins/techdocs/src/home/components/DocsTable.tsx b/plugins/techdocs/src/home/components/DocsTable.tsx index 0e64c2e2e8..83d6f05788 100644 --- a/plugins/techdocs/src/home/components/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/DocsTable.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { useCopyToClipboard } from 'react-use'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { useRouteRef, useApi, configApiRef } from '@backstage/core-plugin-api'; import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; import { formatEntityRefTitle, @@ -34,6 +34,7 @@ import { import * as actionFactories from './actions'; import * as columnFactories from './columns'; import { DocsTableRow } from './types'; +import { toLowerMaybe } from '../../helpers'; export const DocsTable = ({ entities, @@ -50,26 +51,21 @@ export const DocsTable = ({ }) => { const [, copyToClipboard] = useCopyToClipboard(); const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef); - - // Lower-case entity triplets by default, but allow override. - const toLowerMaybe = useApi(configApiRef).getOptionalBoolean( - 'techdocs.legacyUseCaseSensitiveTripletPaths', - ) - ? (str: string) => str - : (str: string) => str.toLocaleLowerCase('en-US'); - + const config = useApi(configApiRef); if (!entities) return null; const documents = entities.map(entity => { const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); - return { entity, resolved: { docsUrl: getRouteToReaderPageFor({ - namespace: toLowerMaybe(entity.metadata.namespace ?? 'default'), - kind: toLowerMaybe(entity.kind), - name: toLowerMaybe(entity.metadata.name), + namespace: toLowerMaybe( + entity.metadata.namespace ?? 'default', + config, + ), + kind: toLowerMaybe(entity.kind, config), + name: toLowerMaybe(entity.metadata.name, config), }), ownedByRelations, ownedByRelationsTitle: ownedByRelations diff --git a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx index fa82527282..ea24a3627f 100644 --- a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx @@ -14,32 +14,30 @@ * limitations under the License. */ -import { render } from '@testing-library/react'; -import React from 'react'; +import React, { ReactNode } from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; import { TechDocsBuildLogs, TechDocsBuildLogsDrawerContent, } from './TechDocsBuildLogs'; -// react-lazylog is based on a react-virtualized component which doesn't -// write the content to the dom, so we mock it. -jest.mock('react-lazylog/build/LazyLog', () => { - return { - default: ({ text }: { text: string }) => { - return

{text}

; - }, - }; -}); +// The inside needs mocking to render in jsdom +jest.mock('react-virtualized-auto-sizer', () => ({ + __esModule: true, + default: (props: { + children: (size: { width: number; height: number }) => ReactNode; + }) => <>{props.children({ width: 400, height: 200 })}, +})); describe('', () => { - it('should render with button', () => { - const rendered = render(); + it('should render with button', async () => { + const rendered = await renderInTestApp(); expect(rendered.getByText(/Show Build Logs/i)).toBeInTheDocument(); expect(rendered.queryByText(/Build Details/i)).not.toBeInTheDocument(); }); - it('should open drawer', () => { - const rendered = render(); + it('should open drawer', async () => { + const rendered = await renderInTestApp(); rendered.getByText(/Show Build Logs/i).click(); expect(rendered.getByText(/Build Details/i)).toBeInTheDocument(); }); @@ -48,7 +46,7 @@ describe('', () => { describe('', () => { it('should render with empty log', async () => { const onClose = jest.fn(); - const rendered = render( + const rendered = await renderInTestApp( , ); expect(rendered.getByText(/Build Details/i)).toBeInTheDocument(); @@ -61,7 +59,7 @@ describe('', () => { it('should render logs', async () => { const onClose = jest.fn(); - const rendered = render( + const rendered = await renderInTestApp( ', () => { expect(onClose).toBeCalledTimes(0); }); - it('should call onClose', () => { + it('should call onClose', async () => { const onClose = jest.fn(); - const rendered = render( + const rendered = await renderInTestApp( , ); rendered.getByTitle('Close the drawer').click(); diff --git a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx index 8c739a9bcf..dc446a55d8 100644 --- a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Progress } from '@backstage/core-components'; +import { LogViewer } from '@backstage/core-components'; import { Button, createStyles, @@ -26,9 +26,7 @@ import { Typography, } from '@material-ui/core'; import Close from '@material-ui/icons/Close'; -import React, { Suspense, useState } from 'react'; - -const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); +import React, { useState } from 'react'; const useDrawerStyles = makeStyles((theme: Theme) => createStyles({ @@ -46,6 +44,9 @@ const useDrawerStyles = makeStyles((theme: Theme) => height: '100%', overflow: 'hidden', }, + logs: { + background: theme.palette.background.default, + }, }), ); @@ -57,6 +58,8 @@ export const TechDocsBuildLogsDrawerContent = ({ onClose: () => void; }) => { const classes = useDrawerStyles(); + const logText = + buildLog.length === 0 ? 'Waiting for logs...' : buildLog.join('\n'); return ( - - }> - - + ); }; diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index f27dba351d..9903ca2b64 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-todo-backend +## 0.1.15 + +### Patch Changes + +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/backend-common@0.9.13 + ## 0.1.14 ### Patch Changes diff --git a/plugins/todo-backend/api-report.md b/plugins/todo-backend/api-report.md index f989755a62..00e243d1a2 100644 --- a/plugins/todo-backend/api-report.md +++ b/plugins/todo-backend/api-report.md @@ -112,7 +112,7 @@ export class TodoScmReader implements TodoReader { options: Omit, ): TodoScmReader; // (undocumented) - readTodos({ url }: ReadTodosOptions): Promise; + readTodos(options: ReadTodosOptions): Promise; } // Warning: (ae-missing-release-tag) "TodoService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index dd69f60072..ecb35920a6 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.14", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,7 +25,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.12", + "@backstage/backend-common": "^0.9.13", "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", @@ -39,7 +39,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.1", "@types/supertest": "^2.0.8", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/todo-backend/src/lib/TodoReader/TodoScmReader.ts b/plugins/todo-backend/src/lib/TodoReader/TodoScmReader.ts index 8442983637..804dd1146d 100644 --- a/plugins/todo-backend/src/lib/TodoReader/TodoScmReader.ts +++ b/plugins/todo-backend/src/lib/TodoReader/TodoScmReader.ts @@ -76,7 +76,8 @@ export class TodoScmReader implements TodoReader { this.integrations = options.integrations; } - async readTodos({ url }: ReadTodosOptions): Promise { + async readTodos(options: ReadTodosOptions): Promise { + const { url } = options; const inFlightRead = this.inFlightReads.get(url); if (inFlightRead) { return inFlightRead.then(read => read.result); @@ -101,9 +102,10 @@ export class TodoScmReader implements TodoReader { } private async doReadTodos( - { url }: ReadTodosOptions, + options: ReadTodosOptions, etag?: string, ): Promise { + const { url } = options; const tree = await this.reader.readTree(url, { etag, filter(filePath, info) { diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index 1a6a352e73..a0f8798d93 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-todo +## 0.1.16 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + - @backstage/plugin-catalog-react@0.6.5 + ## 0.1.15 ### Patch Changes diff --git a/plugins/todo/api-report.md b/plugins/todo/api-report.md index e0fdb8ba58..0784f5d56e 100644 --- a/plugins/todo/api-report.md +++ b/plugins/todo/api-report.md @@ -26,13 +26,7 @@ export const todoApiRef: ApiRef; export class TodoClient implements TodoApi { constructor(options: TodoClientOptions); // (undocumented) - listTodos({ - entity, - offset, - limit, - orderBy, - filters, - }: TodoListOptions): Promise; + listTodos(options: TodoListOptions): Promise; } // @public diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 1fadc213af..10f2b311ca 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.1.15", + "version": "0.1.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,23 +28,24 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.4", + "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/todo/src/api/TodoClient.ts b/plugins/todo/src/api/TodoClient.ts index f75e4b6954..7e4e4c8f79 100644 --- a/plugins/todo/src/api/TodoClient.ts +++ b/plugins/todo/src/api/TodoClient.ts @@ -43,13 +43,8 @@ export class TodoClient implements TodoApi { this.identityApi = options.identityApi; } - async listTodos({ - entity, - offset, - limit, - orderBy, - filters, - }: TodoListOptions): Promise { + async listTodos(options: TodoListOptions): Promise { + const { entity, offset, limit, orderBy, filters } = options; const baseUrl = await this.discoveryApi.getBaseUrl('todo'); const token = await this.identityApi.getIdToken(); diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 8511860dd1..57a6326022 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-user-settings +## 0.3.13 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index feab9dcf93..aaef5eb0a3 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.3.12", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,22 +31,23 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index bf2cdb7a0c..a76282fac8 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-xcmetrics +## 0.2.12 + +### Patch Changes + +- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used. +- 343ef34599: Handle a case where XCode data from backend (before 0.0.8) could be missing +- Updated dependencies + - @backstage/core-components@0.8.0 + - @backstage/core-plugin-api@0.3.0 + ## 0.2.11 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index aa2f6169e3..55488aa8f4 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.11", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.7.6", - "@backstage/core-plugin-api": "^0.2.2", + "@backstage/core-components": "^0.8.0", + "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.3", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -30,16 +30,17 @@ "@material-ui/lab": "4.0.0-alpha.57", "lodash": "^4.17.21", "luxon": "^2.0.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", "react-use": "^17.2.4", "recharts": "^1.8.5" }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, "devDependencies": { - "@backstage/cli": "^0.10.0", - "@backstage/core-app-api": "^0.1.24", - "@backstage/dev-utils": "^0.2.13", - "@backstage/test-utils": "^0.1.23", + "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", + "@backstage/dev-utils": "^0.2.14", + "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/scripts/check-type-dependencies.js b/scripts/check-type-dependencies.js index bb5f3b0967..4db1109145 100755 --- a/scripts/check-type-dependencies.js +++ b/scripts/check-type-dependencies.js @@ -143,7 +143,10 @@ function findTypesPackage(dep, pkg) { */ function findTypeDepErrors(typeDeps, pkg) { const devDeps = mkTypeDepSet(pkg.get('devDependencies')); - const deps = mkTypeDepSet(pkg.get('dependencies')); + const deps = mkTypeDepSet({ + ...pkg.get('dependencies'), + ...pkg.get('peerDependencies'), + }); const errors = []; for (const typeDep of typeDeps) { diff --git a/yarn.lock b/yarn.lock index 98e69c70a9..7a599498d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2181,6 +2181,28 @@ "@backstage/errors" "^0.1.2" cross-fetch "^3.0.6" +"@backstage/core-app-api@^0.1.13", "@backstage/core-app-api@^0.1.16", "@backstage/core-app-api@^0.1.3", "@backstage/core-app-api@^0.1.6": + version "0.1.24" + resolved "https://registry.npmjs.org/@backstage/core-app-api/-/core-app-api-0.1.24.tgz#4cfc366c56de3e698218770eacb59a0aa16c8f05" + integrity sha512-TJ2F+8UjwBQqlSd6y3RpPwdmJfLsvds2OaH3TuiFvjdpogqboIjWGq3nIgxzhe+vxYoWLhoHrMoJYP4IpF7VQQ== + dependencies: + "@backstage/app-defaults" "^0.1.1" + "@backstage/config" "^0.1.11" + "@backstage/core-components" "^0.7.6" + "@backstage/core-plugin-api" "^0.2.2" + "@backstage/theme" "^0.2.14" + "@backstage/types" "^0.1.1" + "@backstage/version-bridge" "^0.1.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@types/prop-types" "^15.7.3" + "@types/react" "*" + prop-types "^15.7.2" + react "^16.12.0" + react-router-dom "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + "@backstage/core-components@^0.3.0": version "0.3.3" resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.3.3.tgz#ec63eac6d789303f90219857849fa1cefe4e0dde" @@ -2359,6 +2381,48 @@ remark-gfm "^1.0.0" zen-observable "^0.8.15" +"@backstage/core-components@^0.7.0", "@backstage/core-components@^0.7.6": + version "0.7.6" + resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.7.6.tgz#2d29480b13c607c8ea8a2821a06326bd05ca3db8" + integrity sha512-aB0ndQDxjNW8Tkzs0rhABd8qF2wLC9f0PWKT3RMh5Tovmg6Y/OOhj+YDzlsPrYJFLwfIwFDC4iA+H1WdkFe7tg== + dependencies: + "@backstage/config" "^0.1.11" + "@backstage/core-plugin-api" "^0.2.2" + "@backstage/errors" "^0.1.5" + "@backstage/theme" "^0.2.14" + "@material-table/core" "^3.1.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + "@types/react" "*" + "@types/react-sparklines" "^1.7.0" + "@types/react-text-truncate" "^0.14.0" + classnames "^2.2.6" + clsx "^1.1.0" + d3-selection "^3.0.0" + d3-shape "^3.0.0" + d3-zoom "^3.0.0" + dagre "^0.8.5" + immer "^9.0.1" + lodash "^4.17.21" + pluralize "^8.0.0" + prop-types "^15.7.2" + qs "^6.9.4" + rc-progress "^3.0.0" + react "^16.12.0" + react-dom "^16.12.0" + react-helmet "6.1.0" + react-hook-form "^7.12.2" + react-markdown "^7.0.1" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-sparklines "^1.7.0" + react-syntax-highlighter "^15.4.3" + react-text-truncate "^0.16.0" + react-use "^17.2.4" + remark-gfm "^2.0.0" + zen-observable "^0.8.15" + "@backstage/core-plugin-api@^0.1.10", "@backstage/core-plugin-api@^0.1.3", "@backstage/core-plugin-api@^0.1.4", "@backstage/core-plugin-api@^0.1.6", "@backstage/core-plugin-api@^0.1.8": version "0.1.13" resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-0.1.13.tgz#583c0fe3440450c304f13dcc85eac3bd80f357d7" @@ -2377,6 +2441,24 @@ react-use "^17.2.4" zen-observable "^0.8.15" +"@backstage/core-plugin-api@^0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-0.2.2.tgz#e746b8595959a9d4acdbe4d6bc5b71d591d0cd1b" + integrity sha512-04TMAX75cBTOMYdKTIgp8FAz4BRrCC9s7YDIBpUM0z+d1UlfCWe48EmP2igPsCt/8apcw38gdR81BPlqzoD6UA== + dependencies: + "@backstage/config" "^0.1.11" + "@backstage/theme" "^0.2.14" + "@backstage/types" "^0.1.1" + "@backstage/version-bridge" "^0.1.0" + "@material-ui/core" "^4.12.2" + "@types/react" "*" + history "^5.0.0" + prop-types "^15.7.2" + react "^16.12.0" + react-router-dom "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + "@backstage/plugin-catalog-react@^0.4.0": version "0.4.6" resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-0.4.6.tgz#f33f3cd734f110d3c547f7eae4e25d14806ec796" @@ -2626,6 +2708,71 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@codemirror/highlight@^0.19.0": + version "0.19.6" + resolved "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.19.6.tgz#7f2e066f83f5649e8e0748a3abe0aaeaf64b8ac2" + integrity sha512-+eibu6on9quY8uN3xJ/n3rH+YIDLlpX7YulVmFvqAIz/ukRQ5tWaBmB7fMixHmnmRIRBRZgB8rNtonuMwZSAHQ== + dependencies: + "@codemirror/language" "^0.19.0" + "@codemirror/rangeset" "^0.19.0" + "@codemirror/state" "^0.19.0" + "@codemirror/view" "^0.19.0" + "@lezer/common" "^0.15.0" + style-mod "^4.0.0" + +"@codemirror/language@^0.19.0": + version "0.19.7" + resolved "https://registry.npmjs.org/@codemirror/language/-/language-0.19.7.tgz#9eef8e827692d93a701b18db9d46a42be34ecca6" + integrity sha512-pNNUtYWMIMG0lUSKyUXJr8U0rFiCKsKFXbA2Oj17PC+S1FY99hV0z1vcntW67ekAIZw9DMEUQnLsKBuIbAUX7Q== + dependencies: + "@codemirror/state" "^0.19.0" + "@codemirror/text" "^0.19.0" + "@codemirror/view" "^0.19.0" + "@lezer/common" "^0.15.5" + "@lezer/lr" "^0.15.0" + +"@codemirror/rangeset@^0.19.0": + version "0.19.2" + resolved "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.2.tgz#d7a999e4273c00fecef4aba8535a426073cdcddf" + integrity sha512-5d+X8LtmeZtfFtKrSx57bIHRUpKv2HD0b74clp4fGA7qJLLfYehF6FGkJJxJb8lKsqAga1gdjjWr0jiypmIxoQ== + dependencies: + "@codemirror/state" "^0.19.0" + +"@codemirror/state@^0.19.0", "@codemirror/state@^0.19.3": + version "0.19.6" + resolved "https://registry.npmjs.org/@codemirror/state/-/state-0.19.6.tgz#d631f041d39ce41b7891b099fca26cb1fdb9763e" + integrity sha512-sqIQZE9VqwQj7D4c2oz9mfLhlT1ElAzGB5lO1lE33BPyrdNy1cJyCIOecT4cn4VeJOFrnjOeu+IftZ3zqdFETw== + dependencies: + "@codemirror/text" "^0.19.0" + +"@codemirror/stream-parser@^0.19.2": + version "0.19.2" + resolved "https://registry.npmjs.org/@codemirror/stream-parser/-/stream-parser-0.19.2.tgz#793428e55aa7b9daa64cb733973e5d5e3d9a2306" + integrity sha512-hBKRQlyu8GUOrY33xZ6/1kAfNZ8ZUm6cX9a7mPx8zAAqnpz/fpksC/qJRrkg1mPMBwxm+JG4fqAwDGJ3gLVniQ== + dependencies: + "@codemirror/highlight" "^0.19.0" + "@codemirror/language" "^0.19.0" + "@codemirror/state" "^0.19.0" + "@codemirror/text" "^0.19.0" + "@lezer/common" "^0.15.0" + "@lezer/lr" "^0.15.0" + +"@codemirror/text@^0.19.0": + version "0.19.5" + resolved "https://registry.npmjs.org/@codemirror/text/-/text-0.19.5.tgz#75033af2476214e79eae22b81ada618815441c18" + integrity sha512-Syu5Xc7tZzeUAM/y4fETkT0zgGr48rDG+w4U38bPwSIUr+L9S/7w2wDE1WGNzjaZPz12F6gb1gxWiSTg9ocLow== + +"@codemirror/view@^0.19.0": + version "0.19.27" + resolved "https://registry.npmjs.org/@codemirror/view/-/view-0.19.27.tgz#76e5dc19ecb4ce53e9fef1d29245040d7ff64183" + integrity sha512-Uz/LecEf7CyvMWaQBlKtbJCYn0hRnEZ2yYvuZVy9YMhmvGmES6ec7FaKw7lDFFOMLwLbBThc9kfw4DCHreHN1w== + dependencies: + "@codemirror/rangeset" "^0.19.0" + "@codemirror/state" "^0.19.3" + "@codemirror/text" "^0.19.0" + style-mod "^4.0.0" + w3c-keyname "^2.2.4" + "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -2984,13 +3131,12 @@ stream-events "^1.0.1" xdg-basedir "^4.0.0" -"@graphiql/toolkit@^0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.3.2.tgz#551753436ada2bc27ea870b7668e5199a958ccfb" - integrity sha512-IweIT9VC8uDovg7kuCO9YqZcnIuWU8IGzrpUisXv6CUNK2Ed1ke8yERDTMmF/rjvLd2DeVZwM8iEOjEs4sUJQw== +"@graphiql/toolkit@^0.4.2": + version "0.4.2" + resolved "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.4.2.tgz#34de819add64672f3f7d4830dffb2094fb8d5366" + integrity sha512-14uG67QrONbRrhXwvBJFsMfcQfexmGhj7dgkputesx9xuPUkcCDNmVULnVA8sGYt8P/rSvjkfQYx3rtfW+GhAQ== dependencies: - "@n1ru4l/push-pull-async-iterable-iterator" "^3.0.0" - graphql-ws "^4.9.0" + "@n1ru4l/push-pull-async-iterable-iterator" "^3.1.0" meros "^1.1.4" "@graphql-codegen/cli@^1.21.3": @@ -3173,6 +3319,16 @@ tslib "~2.2.0" value-or-promise "1.0.6" +"@graphql-tools/batch-execute@^8.3.1": + version "8.3.1" + resolved "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.3.1.tgz#0b74c54db5ac1c5b9a273baefc034c2343ebbb74" + integrity sha512-63kHY8ZdoO5FoeDXYHnAak1R3ysMViMPwWC2XUblFckuVLMUPmB2ONje8rjr2CvzWBHAW8c1Zsex+U3xhKtGIA== + dependencies: + "@graphql-tools/utils" "^8.5.1" + dataloader "2.0.0" + tslib "~2.3.0" + value-or-promise "1.0.11" + "@graphql-tools/code-file-loader@^6.3.1": version "6.3.1" resolved "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-6.3.1.tgz#42dfd4db5b968acdb453382f172ec684fa0c34ed" @@ -3195,6 +3351,18 @@ tslib "~2.2.0" value-or-promise "1.0.6" +"@graphql-tools/delegate@^8.4.1", "@graphql-tools/delegate@^8.4.2": + version "8.4.2" + resolved "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.4.2.tgz#a61d45719855720304e3656800342cfa17d82558" + integrity sha512-CjggOhiL4WtyG2I3kux+1/p8lQxSFHBj0gwa0NxnQ6Vsnpw7Ig5VP1ovPnitFuBv2k4QdC37Nj2xv2n7DRn8fw== + dependencies: + "@graphql-tools/batch-execute" "^8.3.1" + "@graphql-tools/schema" "^8.3.1" + "@graphql-tools/utils" "^8.5.3" + dataloader "2.0.0" + tslib "~2.3.0" + value-or-promise "1.0.11" + "@graphql-tools/git-loader@^6.2.6": version "6.2.6" resolved "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-6.2.6.tgz#c2226f4b8f51f1c05c9ab2649ba32d49c68cd077" @@ -3223,6 +3391,17 @@ "@graphql-tools/utils" "^7.0.0" tslib "~2.1.0" +"@graphql-tools/graphql-file-loader@^7.3.2": + version "7.3.3" + resolved "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.3.3.tgz#7cee2f84f08dc13fa756820b510248b857583d36" + integrity sha512-6kUJZiNpYKVhum9E5wfl5PyLLupEDYdH7c8l6oMrk6c7EPEVs6iSUyB7yQoWrtJccJLULBW2CRQ5IHp5JYK0mA== + dependencies: + "@graphql-tools/import" "^6.5.7" + "@graphql-tools/utils" "^8.5.1" + globby "^11.0.3" + tslib "~2.3.0" + unixify "^1.0.0" + "@graphql-tools/graphql-tag-pluck@^6.2.6", "@graphql-tools/graphql-tag-pluck@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-6.5.1.tgz#5fb227dbb1e19f4b037792b50f646f16a2d4c686" @@ -3242,6 +3421,15 @@ resolve-from "5.0.0" tslib "~2.2.0" +"@graphql-tools/import@^6.5.7": + version "6.6.1" + resolved "https://registry.npmjs.org/@graphql-tools/import/-/import-6.6.1.tgz#2a7e1ceda10103ffeb8652a48ddc47150b035485" + integrity sha512-i9WA6k+erJMci822o9w9DoX+uncVBK60LGGYW8mdbhX0l7wEubUpA000thJ1aarCusYh0u+ZT9qX0HyVPXu25Q== + dependencies: + "@graphql-tools/utils" "8.5.3" + resolve-from "5.0.0" + tslib "~2.3.0" + "@graphql-tools/json-file-loader@^6.0.0", "@graphql-tools/json-file-loader@^6.2.6": version "6.2.6" resolved "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-6.2.6.tgz#830482cfd3721a0799cbf2fe5b09959d9332739a" @@ -3250,6 +3438,16 @@ "@graphql-tools/utils" "^7.0.0" tslib "~2.0.1" +"@graphql-tools/json-file-loader@^7.3.2": + version "7.3.3" + resolved "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-7.3.3.tgz#45cfde77b9dc4ab6c21575305ae537d2814d237f" + integrity sha512-CN2Qk9rt+Gepa3rb3X/mpxYA5MIYLwZBPj2Njw6lbZ6AaxG+O1ArDCL5ACoiWiBimn1FCOM778uhRM9znd0b3Q== + dependencies: + "@graphql-tools/utils" "^8.5.1" + globby "^11.0.3" + tslib "~2.3.0" + unixify "^1.0.0" + "@graphql-tools/load@^6.0.0", "@graphql-tools/load@^6.2.8": version "6.2.8" resolved "https://registry.npmjs.org/@graphql-tools/load/-/load-6.2.8.tgz#16900fb6e75e1d075cad8f7ea439b334feb0b96a" @@ -3265,6 +3463,16 @@ unixify "1.0.0" valid-url "1.0.9" +"@graphql-tools/load@^7.4.1": + version "7.4.1" + resolved "https://registry.npmjs.org/@graphql-tools/load/-/load-7.4.1.tgz#aa572fcef11d6028097b6ef39c13fa9d62e5a441" + integrity sha512-UvBodW5hRHpgBUBVz5K5VIhJDOTFIbRRAGD6sQ2l9J5FDKBEs3u/6JjZDzbdL96br94D5cEd2Tk6auaHpTn7mQ== + dependencies: + "@graphql-tools/schema" "8.3.1" + "@graphql-tools/utils" "^8.5.1" + p-limit "3.1.0" + tslib "~2.3.0" + "@graphql-tools/merge@^6.0.0", "@graphql-tools/merge@^6.2.12", "@graphql-tools/merge@^6.2.14": version "6.2.14" resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-6.2.14.tgz#694e2a2785ba47558e5665687feddd2935e9d94e" @@ -3274,6 +3482,14 @@ "@graphql-tools/utils" "^7.7.0" tslib "~2.2.0" +"@graphql-tools/merge@^8.2.1": + version "8.2.1" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.1.tgz#bf83aa06a0cfc6a839e52a58057a84498d0d51ff" + integrity sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA== + dependencies: + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + "@graphql-tools/optimize@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-1.0.1.tgz#9933fffc5a3c63f95102b1cb6076fb16ac7bb22d" @@ -3317,6 +3533,16 @@ relay-compiler "10.1.0" tslib "~2.0.1" +"@graphql-tools/schema@8.3.1", "@graphql-tools/schema@^8.3.1": + version "8.3.1" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.1.tgz#1ee9da494d2da457643b3c93502b94c3c4b68c74" + integrity sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ== + dependencies: + "@graphql-tools/merge" "^8.2.1" + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + value-or-promise "1.0.11" + "@graphql-tools/schema@^7.0.0", "@graphql-tools/schema@^7.1.5": version "7.1.5" resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-7.1.5.tgz#07b24e52b182e736a6b77c829fc48b84d89aa711" @@ -3351,6 +3577,38 @@ valid-url "1.0.9" ws "7.4.5" +"@graphql-tools/url-loader@^7.4.2": + version "7.5.3" + resolved "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.5.3.tgz#a594be40e3bc68d22f76746356e7f0b8117b7137" + integrity sha512-VKMRJ4TOeVIdulkCLGSBUr4stRRwOGcVRXDeoUF+86K32Ufo0H2V0lz7QwS/bCl8GXV19FMgHZCDl4BMJyOXEA== + dependencies: + "@graphql-tools/delegate" "^8.4.1" + "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/wrap" "^8.3.1" + "@n1ru4l/graphql-live-query" "0.9.0" + "@types/websocket" "1.0.4" + "@types/ws" "^8.0.0" + cross-undici-fetch "^0.0.26" + dset "^3.1.0" + extract-files "11.0.0" + graphql-sse "^1.0.1" + graphql-ws "^5.4.1" + isomorphic-ws "4.0.1" + meros "1.1.4" + subscriptions-transport-ws "^0.11.0" + sync-fetch "0.3.1" + tslib "~2.3.0" + valid-url "1.0.9" + value-or-promise "1.0.11" + ws "8.3.0" + +"@graphql-tools/utils@8.5.3", "@graphql-tools/utils@^8.5.1", "@graphql-tools/utils@^8.5.3": + version "8.5.3" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.3.tgz#404062e62cae9453501197039687749c4885356e" + integrity sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg== + dependencies: + tslib "~2.3.0" + "@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.1.0", "@graphql-tools/utils@^7.1.2", "@graphql-tools/utils@^7.5.0", "@graphql-tools/utils@^7.7.0", "@graphql-tools/utils@^7.7.1", "@graphql-tools/utils@^7.8.1", "@graphql-tools/utils@^7.9.0", "@graphql-tools/utils@^7.9.1": version "7.10.0" resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-7.10.0.tgz#07a4cb5d1bec1ff1dc1d47a935919ee6abd38699" @@ -3371,6 +3629,17 @@ tslib "~2.2.0" value-or-promise "1.0.6" +"@graphql-tools/wrap@^8.3.1": + version "8.3.2" + resolved "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-8.3.2.tgz#d3bcecb7529d071e4ecc4dfc75b9566e3da79d4f" + integrity sha512-7DcOBFB+Dd84x9dxSm7qS4iJONMyfLnCJb8A19vGPffpu4SMJ3sFcgwibKFu5l6mMUiigKgXna2RRgWI+02bKQ== + dependencies: + "@graphql-tools/delegate" "^8.4.2" + "@graphql-tools/schema" "^8.3.1" + "@graphql-tools/utils" "^8.5.3" + tslib "~2.3.0" + value-or-promise "1.0.11" + "@grpc/grpc-js@~1.3.0": version "1.3.2" resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.2.tgz#eae97e6daf5abd49a7818aadeca0744dfb1ebca1" @@ -4377,6 +4646,18 @@ npmlog "^4.1.2" write-file-atomic "^3.0.3" +"@lezer/common@^0.15.0", "@lezer/common@^0.15.5": + version "0.15.10" + resolved "https://registry.npmjs.org/@lezer/common/-/common-0.15.10.tgz#662da668f46244fb20bfaada67b43b3d0463b344" + integrity sha512-vlr+be73zTDoQBIknBVOh/633tmbQcjxUu9PIeVeYESeBK3V6TuBW96RRFg93Y2cyK9lglz241gOgSn452HFvA== + +"@lezer/lr@^0.15.0": + version "0.15.5" + resolved "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.5.tgz#4bce44169c441d9dda7be398f5202ea65c5f1138" + integrity sha512-DEcLyhdmBxD1foQe7RegLrSlfS/XaTMGLkO5evkzHWAQKh/JnFWp7j7iNB7s2EpxzRrBCh0U+W7JDCeFhv2mng== + dependencies: + "@lezer/common" "^0.15.0" + "@manypkg/find-root@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz#a62d8ed1cd7e7d4c11d9d52a8397460b5d4ad29f" @@ -4430,7 +4711,7 @@ react-beautiful-dnd "^13.0.0" react-double-scrollbar "0.0.15" -"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2": +"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.2": version "4.12.3" resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== @@ -4535,13 +4816,6 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" -"@mattiasbuelens/web-streams-polyfill@^0.2.0": - version "0.2.1" - resolved "https://registry.npmjs.org/@mattiasbuelens/web-streams-polyfill/-/web-streams-polyfill-0.2.1.tgz#d7c4aa94f98084ec0787be084d47167d62ea5f67" - integrity sha512-oKuFCQFa3W7Hj7zKn0+4ypI8JFm4ZKIoncwAC6wd5WwFW2sL7O1hpPoJdSWpynQ4DJ4lQ6MvFoVDmCLilonDFg== - dependencies: - "@types/whatwg-streams" "^0.0.7" - "@mdx-js/mdx@^1.6.22": version "1.6.22" resolved "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" @@ -4674,7 +4948,12 @@ outvariant "^1.2.0" strict-event-emitter "^0.2.0" -"@n1ru4l/push-pull-async-iterable-iterator@^3.0.0": +"@n1ru4l/graphql-live-query@0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" + integrity sha512-BTpWy1e+FxN82RnLz4x1+JcEewVdfmUhV1C6/XYD5AjS7PQp9QFF7K8bCD6gzPTr2l+prvqOyVueQhFJxB1vfg== + +"@n1ru4l/push-pull-async-iterable-iterator@^3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@n1ru4l/push-pull-async-iterable-iterator/-/push-pull-async-iterable-iterator-3.1.0.tgz#be450c97d1c7cd6af1a992d53232704454345df9" integrity sha512-K4scWxGhdQM0masHHy4gIQs2iGiLEXCrXttumknyPJqtdl4J179BjpibWSSQ1fxKdCcHgIlCTKXJU6cMM6D6Wg== @@ -5241,29 +5520,6 @@ resolved "https://registry.npmjs.org/@rjsf/material-ui/-/material-ui-3.2.1.tgz#84fbf322485aee3a84101e189161f0687779ec8d" integrity sha512-8UiDeDbjCImFSfOegGu13otQ7OdP9FOYpcLjeouppnhs+MPeIEAtYS+jCcBKmi3reyTagC15/KVSRhde1wS1vg== -"@roadiehq/backstage-plugin-buildkite@^1.0.8": - version "1.0.8" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-1.0.8.tgz#c377ae194682426a957366e85263749ff75b8db1" - integrity sha512-v3OOQj5Ksvs/8SZcNBgq6bzmyJvMIzdGsQrwW8uaLgOX076T0nmK8c3Ojz3w1opymEl3s20sLxLUXjhd7V/nIA== - dependencies: - "@backstage/catalog-model" "^0.9.0" - "@backstage/core-app-api" "^0.1.3" - "@backstage/core-components" "^0.3.0" - "@backstage/core-plugin-api" "^0.1.3" - "@backstage/plugin-catalog-react" "^0.4.0" - "@backstage/theme" "^0.2.6" - "@material-ui/core" "^4.12.1" - "@material-ui/icons" "^4.11.2" - "@material-ui/lab" "4.0.0-alpha.57" - history "^5.0.0" - moment "^2.29.1" - react "^16.13.1" - react-dom "^16.13.1" - react-lazylog "^4.5.2" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-use "^17.2.4" - "@roadiehq/backstage-plugin-github-insights@^1.1.23": version "1.2.2" resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-1.2.2.tgz#09d958ed15adbb598afda34187f45deedec2264d" @@ -6770,6 +7026,13 @@ dependencies: "@types/node" "*" +"@types/ansi-regex@^5.0.0": + version "5.0.0" + resolved "https://registry.npmjs.org/@types/ansi-regex/-/ansi-regex-5.0.0.tgz#569a5189a92cc46d63fb2ad91e6b130f33d999c1" + integrity sha512-SQafVL3pXFh/5qq/nN6p5858g//zSVzcb8JzCLtoVxm8YNPggMQfEIm7aaTNysxpw1S+lFTaW8kv+aR0/CEhCA== + dependencies: + ansi-regex "*" + "@types/archiver@^5.1.0": version "5.3.0" resolved "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.0.tgz#2b34ba56d4d7102d256b922c7e91e09eab79db6f" @@ -7431,7 +7694,7 @@ dependencies: "@types/json-schema" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@7.0.9", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== @@ -7832,14 +8095,6 @@ dependencies: "@types/react" "*" -"@types/react-lazylog@^4.5.0": - version "4.5.1" - resolved "https://registry.npmjs.org/@types/react-lazylog/-/react-lazylog-4.5.1.tgz#babb5d814f7035b5434518769975e12f299356a8" - integrity sha512-g4yeosa1zYhu2BUJmuu2H2o0dsdRj0o8Omw3pBiVHdLHJaeYIyArvyMRR3bI/MxZxG4EaiRl8AOQ6zeM8P46jA== - dependencies: - "@types/react" "*" - immutable ">=3.8.2" - "@types/react-redux@^7.1.16": version "7.1.19" resolved "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz#477bd0a9b01bae6d6bf809418cdfa7d3c16d4c62" @@ -7892,7 +8147,21 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.0": +"@types/react-virtualized-auto-sizer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz#b3187dae1dfc4c15880c9cfc5b45f2719ea6ebd4" + integrity sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong== + dependencies: + "@types/react" "*" + +"@types/react-window@^1.8.5": + version "1.8.5" + resolved "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1" + integrity sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@>=16.9.0", "@types/react@^16.13.1 || ^17.0.0": version "16.14.18" resolved "https://registry.npmjs.org/@types/react/-/react-16.14.18.tgz#b2bcea05ee244fde92d409f91bd888ca8e54b20f" integrity sha512-eeyqd1mqoG43mI0TvNKy9QNf1Tjz3DEOsRP3rlPo35OeMIt05I+v9RR8ZvL2GuYZeF2WAcLXJZMzu6zdz3VbtQ== @@ -8276,10 +8545,12 @@ dependencies: "@types/node" "*" -"@types/whatwg-streams@^0.0.7": - version "0.0.7" - resolved "https://registry.npmjs.org/@types/whatwg-streams/-/whatwg-streams-0.0.7.tgz#28bfe73dc850562296367249c4b32a50db81e9d3" - integrity sha512-6sDiSEP6DWcY2ZolsJ2s39ZmsoGQ7KVwBDI3sESQsEm9P2dHTcqnDIHRZFRNtLCzWp7hCFGqYbw5GyfpQnJ01A== +"@types/websocket@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8" + integrity sha512-qn1LkcFEKK8RPp459jkjzsfpbsx36BBt3oC3pITYtkoBw/aVX+EZFa5j3ThCRTNpLFvIMr5dSTD4RaMdilIOpA== + dependencies: + "@types/node" "*" "@types/ws@^6.0.1": version "6.0.4" @@ -8295,6 +8566,13 @@ dependencies: "@types/node" "*" +"@types/ws@^8.0.0": + version "8.2.2" + resolved "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz#7c5be4decb19500ae6b3d563043cd407bf366c21" + integrity sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg== + dependencies: + "@types/node" "*" + "@types/xml2js@*", "@types/xml2js@^0.4.7": version "0.4.8" resolved "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.8.tgz#84c120c864a5976d0b5cf2f930a75d850fc2b03a" @@ -9017,6 +9295,11 @@ ansi-html@0.0.7, ansi-html@^0.0.7: resolved "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= +ansi-regex@*, ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -9037,11 +9320,6 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -11237,7 +11515,7 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -clsx@^1.0.1, clsx@^1.0.2, clsx@^1.0.4, clsx@^1.1.0: +clsx@^1.0.2, clsx@^1.0.4, clsx@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== @@ -11273,13 +11551,13 @@ code-point-at@^1.0.0: resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemirror-graphql@^1.0.3: - version "1.1.0" - resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-1.1.0.tgz#dd22ddf7761efa9131fa99a70a4a85fe653484e5" - integrity sha512-bp2XUg7epL07kJcylM8VCISK6X+rFsHL2lUkPQAw2v721MVhn+80FgjMP8tiZCOfJgHn1+JgsA71L5nOHWgUdA== +codemirror-graphql@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-1.2.8.tgz#4d3845d786665776eb5c44b0948bfa8f9860077f" + integrity sha512-/SlF24YNWirA8SyyaiFkrwPVIhPS/OkMNRHkL3TeZKhJIv3wuGAa90B4DYqY17MBN2QN1+RYd/71eYZD/fvj1Q== dependencies: - graphql-language-service-interface "^2.9.0" - graphql-language-service-parser "^1.10.0" + "@codemirror/stream-parser" "^0.19.2" + graphql-language-service "^4.1.1" codemirror@^5.58.2: version "5.63.3" @@ -11881,6 +12159,17 @@ cosmiconfig@7.0.0, cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + cosmiconfig@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" @@ -12039,6 +12328,16 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" +cross-undici-fetch@^0.0.26: + version "0.0.26" + resolved "https://registry.npmjs.org/cross-undici-fetch/-/cross-undici-fetch-0.0.26.tgz#29d93d56609f4d2334f9d5333d23ef7a242842a7" + integrity sha512-aMDRrLbWr0TGXfY92stlV+XOGpskeqFmWmrKSWsnc8w6gK5LPE83NBh7O7N6gCb2xjwHcm1Yn2nBXMEVH2RBcA== + dependencies: + abort-controller "^3.0.0" + form-data "^4.0.0" + node-fetch "^2.6.5" + undici "^4.9.3" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -13175,7 +13474,7 @@ dom-helpers@^3.4.0: dependencies: "@babel/runtime" "^7.1.2" -dom-helpers@^5.0.0, dom-helpers@^5.0.1: +dom-helpers@^5.0.1: version "5.1.4" resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz#4609680ab5c79a45f2531441f1949b79d6587f4b" integrity sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A== @@ -14547,6 +14846,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-files@11.0.0: + version "11.0.0" + resolved "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" + integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== + extract-files@9.0.0, extract-files@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" @@ -14732,11 +15036,6 @@ fecha@^4.2.0: resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== -fetch-readablestream@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/fetch-readablestream/-/fetch-readablestream-0.2.0.tgz#eaa6d1a76b12de2d4731a343393c6ccdcfe2c795" - integrity sha512-qu4mXWf4wus4idBIN/kVH+XSer8IZ9CwHP+Pd7DL7TuKNC1hP7ykon4kkBjwJF3EMX2WsFp4hH7gU7CyL7ucXw== - figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -15893,19 +16192,19 @@ grapheme-splitter@^1.0.4: resolved "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -graphiql@^1.0.0-alpha.10: - version "1.4.7" - resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.4.7.tgz#6a35acf0786d7518fbb986b75bf0a3d752c19c1a" - integrity sha512-oHsBTzdWTbRJhqazbjrC6wY7YInViErAeXLqetCxdFFu2Zk5FV3V3rs7KPrCyr7kM6lW0nfXMzIfKuIgxAqx7g== +graphiql@^1.5.12: + version "1.5.13" + resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.5.13.tgz#7706c56504213598641e8300a612a7dccaba95d5" + integrity sha512-lfG7FZzjDb4jwAP5mU+IiYvkTcZ/OygbIlk6JJrB0CPBqMl4k/3dEaZFmyKjmy54xTo8bkiH28VgpcF8VPc1eg== dependencies: - "@graphiql/toolkit" "^0.3.2" + "@graphiql/toolkit" "^0.4.2" codemirror "^5.58.2" - codemirror-graphql "^1.0.3" + codemirror-graphql "^1.2.8" copy-to-clipboard "^3.2.0" dset "^3.1.0" entities "^2.0.0" escape-html "^1.0.3" - graphql-language-service "^3.1.6" + graphql-language-service "^4.1.1" markdown-it "^12.2.0" graphlib@^2.1.8: @@ -15932,6 +16231,23 @@ graphql-config@^3.0.2, graphql-config@^3.3.0: minimatch "3.0.4" string-env-interpolation "1.0.1" +graphql-config@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/graphql-config/-/graphql-config-4.1.0.tgz#a3b28d3fb537952ebeb69c75e4430605a10695e3" + integrity sha512-Myqay6pmdcmX3KqoH+bMbeKZ1cTODpHS2CxF1ZzNnfTE+YUpGTcp01bOw6LpzamRb0T/WTYtGFbZeXGo9Hab2Q== + dependencies: + "@endemolshinegroup/cosmiconfig-typescript-loader" "3.0.2" + "@graphql-tools/graphql-file-loader" "^7.3.2" + "@graphql-tools/json-file-loader" "^7.3.2" + "@graphql-tools/load" "^7.4.1" + "@graphql-tools/merge" "^8.2.1" + "@graphql-tools/url-loader" "^7.4.2" + "@graphql-tools/utils" "^8.5.1" + cosmiconfig "7.0.1" + cosmiconfig-toml-loader "1.0.0" + minimatch "3.0.4" + string-env-interpolation "1.0.1" + graphql-extensions@^0.15.0: version "0.15.0" resolved "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.15.0.tgz#3f291f9274876b0c289fa4061909a12678bd9817" @@ -15941,63 +16257,51 @@ graphql-extensions@^0.15.0: apollo-server-env "^3.1.0" apollo-server-types "^0.9.0" -graphql-language-service-interface@^2.9.0: - version "2.9.1" - resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.9.1.tgz#be0b11b06b78730ea9d250e0e2290e7ed9c8d283" - integrity sha512-yGsE67fxJBXxY82+rLDMvUpmzpOUM8XFB+k+xOTUyABWs27osKaoGiuDDXAVGg1adhm+cpunWbipe763ZJkAVA== +graphql-language-service-interface@^2.10.1: + version "2.10.1" + resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.10.1.tgz#0f81a3da576bad61da878b59c228901236358426" + integrity sha512-2n/nrt0QD8UnxzDKKHWomYuLK9uxGxyPztA6wI24Kng8Iw7jQk/doIti63z4xPKNi4CtbumSjk1TRYUZ/bgViw== dependencies: - graphql-language-service-parser "^1.10.0" - graphql-language-service-types "^1.8.3" - graphql-language-service-utils "^2.6.0" + graphql-config "^4.1.0" + graphql-language-service-parser "^1.10.4" + graphql-language-service-types "^1.8.7" + graphql-language-service-utils "^2.7.1" vscode-languageserver-types "^3.15.1" -graphql-language-service-parser@^1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.10.0.tgz#116f4be849754f6afb4c196421a43fe96d87b278" - integrity sha512-cLExv0EjqT2hsKdwVTPmKU6eMfjZAjxqywgCPnWD48eJn6tyuePMyG7ye+jpX1PRPPx/cDHfFJGf8sUclchvng== +graphql-language-service-parser@^1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.10.4.tgz#b2979deefc5c0df571dacd409b2d5fbf1cdf7a9d" + integrity sha512-duDE+0aeKLFVrb9Kf28U84ZEHhHcvTjWIT6dJbIAQJWBaDoht0D4BK9EIhd94I3DtKRc1JCJb2+70y1lvP/hiA== dependencies: - graphql-language-service-types "^1.8.0" + graphql-language-service-types "^1.8.7" -graphql-language-service-types@^1.8.0: - version "1.8.1" - resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.1.tgz#963810010924f2b5eaea415d5b8eb0b7d42c479b" - integrity sha512-IpYS0mEHEmRsFlq+loWCpSYYYizAID7Alri6GoFN1QqUdux+8rp1Tkp2NGsGDpDmm3Dbz5ojmJWzNWQGpuwveA== - -graphql-language-service-types@^1.8.2: - version "1.8.2" - resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.2.tgz#50ae56f69cc24fcfc3daa129b68b0eb9421e8578" - integrity sha512-Sj07RHnMwAhEvAt7Jdt1l/x56ZpoNh+V6g+T58CF6GiYqI5l4vXqqRB4d4xHDcNQX98GpJfnf3o8BqPgP3C5Sw== - -graphql-language-service-types@^1.8.3: - version "1.8.3" - resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.3.tgz#d7d688d74c122c4d9cc4cceae761a1f2a3c396a1" - integrity sha512-m+RHnlGkKDcesW/gC4M7I2pSmWJB84uWS6LtnjplO/07JN312nJCJYCwV/DBny2m1fmSOxN7H/o+JW0l56KwBA== - -graphql-language-service-utils@^2.5.3: - version "2.5.3" - resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.5.3.tgz#185f4f65cf8c010871eb9405452a3a0bfdf88748" - integrity sha512-ydevEZ0AgzEKQF3hiCbLXuS0o7189Ww/T30WtCKCLaRHDYk9Yyb2PZWdhSTWLxYZTaX2TccV6NtFWvzIC7UP3g== +graphql-language-service-types@^1.8.7: + version "1.8.7" + resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.7.tgz#f5e909e6d9334ea2d8d1f7281b695b6f5602c07f" + integrity sha512-LP/Mx0nFBshYEyD0Ny6EVGfacJAGVx+qXtlJP4hLzUdBNOGimfDNtMVIdZANBXHXcM41MDgMHTnyEx2g6/Ttbw== dependencies: - graphql-language-service-types "^1.8.0" + graphql-config "^4.1.0" + vscode-languageserver-types "^3.15.1" + +graphql-language-service-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.7.1.tgz#c97c8d744a761480aba7e03e4a42adf28b6fce39" + integrity sha512-Wci5MbrQj+6d7rfvbORrA9uDlfMysBWYaG49ST5TKylNaXYFf3ixFOa74iM1KtM9eidosUbI3E1JlWi0JaidJA== + dependencies: + "@types/json-schema" "7.0.9" + graphql-language-service-types "^1.8.7" nullthrows "^1.0.0" -graphql-language-service-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.6.0.tgz#d04904641248167ccbb381d8705ba97daa784954" - integrity sha512-idqwmbREixhDuQMcYp8WH0btQT02xZny8MO/HduNTVjnPrmTYnZUbpZ9AejdflmaKoS0o8nNvgXQ0GpIOzbG5g== +graphql-language-service@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-4.1.1.tgz#8093655c23af6a3f3eee3f92e6a5b0a3e2a21d70" + integrity sha512-7XP+XSzTnpnmh+EYbofnK/YdSaI7/mj7bS8ffP3A1UQtNBLb9mUErgYju6VegcV6Df0bJObLG+XxSBSlgV4kXQ== dependencies: - graphql-language-service-types "^1.8.3" - nullthrows "^1.0.0" - -graphql-language-service@^3.1.6: - version "3.2.0" - resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-3.2.0.tgz#e0eb6d5dea2cab92549a253d7a6b4fa0cce178b7" - integrity sha512-xM5Ua5p7ttG/oEaDy2zk35FP2O2I9qD2N0DOrjCDUVDRC06FNDG+/CvF4qX9+i8DWOI65xch5vAhSQEfS2jFsA== - dependencies: - graphql-language-service-interface "^2.9.0" - graphql-language-service-parser "^1.10.0" - graphql-language-service-types "^1.8.2" - graphql-language-service-utils "^2.5.3" + graphql-language-service-interface "^2.10.1" + graphql-language-service-parser "^1.10.4" + graphql-language-service-types "^1.8.7" + graphql-language-service-utils "^2.7.1" + picomatch "^2.3.0" graphql-request@^3.3.0: version "3.4.0" @@ -16008,6 +16312,11 @@ graphql-request@^3.3.0: extract-files "^9.0.0" form-data "^3.0.0" +graphql-sse@^1.0.1: + version "1.0.6" + resolved "https://registry.npmjs.org/graphql-sse/-/graphql-sse-1.0.6.tgz#4f98e0a06f2020542ed054399116108491263224" + integrity sha512-y2mVBN2KwNrzxX2KBncQ6kzc6JWvecxuBernrl0j65hsr6MAS3+Yn8PTFSOgRmtolxugepxveyZVQEuaNEbw3w== + graphql-subscriptions@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.1.0.tgz#5f2fa4233eda44cf7570526adfcf3c16937aef11" @@ -16057,15 +16366,10 @@ graphql-ws@^4.4.1: resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-4.7.0.tgz#b323fbf35a3736eed85dac24c0054d6d10c93e62" integrity sha512-Md8SsmC9ZlsogFPd3Ot8HbIAAqsHh8Xoq7j4AmcIat1Bh6k91tjVyQvA0Au1/BolXSYq+RDvib6rATU2Hcf1Xw== -graphql-ws@^4.9.0: - version "4.9.0" - resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-4.9.0.tgz#5cfd8bb490b35e86583d8322f5d5d099c26e365c" - integrity sha512-sHkK9+lUm20/BGawNEWNtVAeJzhZeBg21VmvmLoT5NdGVeZWv5PdIhkcayQIAgjSyyQ17WMKmbDijIPG2On+Ag== - -graphql@15.5.0: - version "15.5.0" - resolved "https://registry.npmjs.org/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5" - integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA== +graphql-ws@^5.4.1: + version "5.5.5" + resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.5.5.tgz#f375486d3f196e2a2527b503644693ae3a8670a9" + integrity sha512-hvyIS71vs4Tu/yUYHPvGXsTgo0t3arU820+lT5VjZS2go0ewp2LqyCgxEN56CzOG7Iys52eRhHBiD1gGRdiQtw== graphql@^15.3.0: version "15.5.1" @@ -16077,6 +16381,11 @@ graphql@^15.5.1: resolved "https://registry.npmjs.org/graphql/-/graphql-15.6.1.tgz#9125bdf057553525da251e19e96dab3d3855ddfc" integrity sha512-3i5lu0z6dRvJ48QP9kFxBkJ7h4Kso7PS8eahyTFz5Jm6CvQfLtNIE8LX9N6JLnXTuwR+sIYnXzaWp6anOg0QQw== +graphql@^16.0.0: + version "16.0.1" + resolved "https://registry.npmjs.org/graphql/-/graphql-16.0.1.tgz#93a13cd4e0e38ca8d0832e79614c8578bfd34f10" + integrity sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg== + grouped-queue@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/grouped-queue/-/grouped-queue-2.0.0.tgz#a2c6713f2171e45db2c300a3a9d7c119d694dac8" @@ -16793,7 +17102,7 @@ immer@^9.0.1, immer@^9.0.6: resolved "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz#b6156bd7db55db7abc73fd2fdadf4e579a701075" integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== -immutable@>=3.8.2, immutable@^3.8.2, immutable@^3.x.x: +immutable@^3.x.x: version "3.8.2" resolved "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= @@ -19724,7 +20033,7 @@ longest-streak@^3.0.0: resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.0.tgz#f127e2bded83caa6a35ac5f7a2f2b2f94b36f3dc" integrity sha512-XhUjWR5CFaQ03JOP+iSDS9koy8T5jfoImCZ4XprElw3BXsSk4MpVYOLw/6LTDKZhO13PlAXnB5gS4MHQTpkSOw== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -20270,6 +20579,11 @@ memjs@^1.3.0: resolved "https://registry.npmjs.org/memjs/-/memjs-1.3.0.tgz#b7959b4ff3770e4c785463fd147f1e4fafd47a24" integrity sha512-y/V9a0auepA9Lgyr4QieK6K2FczjHucEdTpSS+hHVNmVEkYxruXhkHu8n6DSRQ4HXHEE3cc6Sf9f88WCJXGXsQ== +"memoize-one@>=3.1.1 <6": + version "5.2.1" + resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + memoize-one@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" @@ -20961,11 +21275,6 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" -mitt@^1.1.2: - version "1.2.0" - resolved "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d" - integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw== - mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -21373,6 +21682,13 @@ node-fetch@2.6.1, node-fetch@^2.3.0, node-fetch@^2.6.0, node-fetch@^2.6.1: resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@^2.6.5: + version "2.6.6" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + dependencies: + whatwg-url "^5.0.0" + node-forge@^0.10.0: version "0.10.0" resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" @@ -22908,7 +23224,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -24039,9 +24355,9 @@ raw-loader@^4.0.2: schema-utils "^3.0.0" rc-progress@^3.0.0: - version "3.1.3" - resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.1.3.tgz#d77d8fd26d9d948d72c2a28b64b71a6e86df2426" - integrity sha512-Jl4fzbBExHYMoC6HBPzel0a9VmhcSXx24LVt/mdhDM90MuzoMCJjXZAlhA0V0CJi+SKjMhfBoIQ6Lla1nD4QNw== + version "3.1.4" + resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.1.4.tgz#66040d0fae7d8ced2b38588378eccb2864bad615" + integrity sha512-XBAif08eunHssGeIdxMXOmRQRULdHaDdIFENQ578CMb4dyewahmmfJRyab+hw4KH4XssEzzYOkAInTLS7JJG+Q== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.6" @@ -24300,21 +24616,6 @@ react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-i resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-lazylog@^4.5.2, react-lazylog@^4.5.3: - version "4.5.3" - resolved "https://registry.npmjs.org/react-lazylog/-/react-lazylog-4.5.3.tgz#289e24995b5599e75943556ac63f5e2c04d0001e" - integrity sha512-lyov32A/4BqihgXgtNXTHCajXSXkYHPlIEmV8RbYjHIMxCFSnmtdg4kDCI3vATz7dURtiFTvrw5yonHnrS+NNg== - dependencies: - "@mattiasbuelens/web-streams-polyfill" "^0.2.0" - fetch-readablestream "^0.2.0" - immutable "^3.8.2" - mitt "^1.1.2" - prop-types "^15.6.1" - react-string-replace "^0.4.1" - react-virtualized "^9.21.0" - text-encoding-utf-8 "^1.0.1" - whatwg-fetch "^2.0.4" - react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -24446,13 +24747,6 @@ react-sparklines@^1.7.0: dependencies: prop-types "^15.5.10" -react-string-replace@^0.4.1: - version "0.4.4" - resolved "https://registry.npmjs.org/react-string-replace/-/react-string-replace-0.4.4.tgz#24006fbe0db573d5be583133df38b1a735cb4225" - integrity sha512-FAMkhxmDpCsGTwTZg7p/2v+/GTmxAp73so3fbSvlAcBBX36ujiGRNEaM/1u+jiYQrArhns+7eE92g2pi5E5FUA== - dependencies: - lodash "^4.17.4" - react-syntax-highlighter@^13.5.3: version "13.5.3" resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz#9712850f883a3e19eb858cf93fad7bb357eea9c6" @@ -24546,19 +24840,20 @@ react-use@^17.2.4: ts-easing "^0.2.0" tslib "^2.1.0" -react-virtualized@^9.21.0: - version "9.21.2" - resolved "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.21.2.tgz#02e6df65c1e020c8dbf574ec4ce971652afca84e" - integrity sha512-oX7I7KYiUM7lVXQzmhtF4Xg/4UA5duSA+/ZcAvdWlTLFCoFYq1SbauJT5gZK9cZS/wdYR6TPGpX/dqzvTqQeBA== - dependencies: - babel-runtime "^6.26.0" - clsx "^1.0.1" - dom-helpers "^5.0.0" - loose-envify "^1.3.0" - prop-types "^15.6.0" - react-lifecycles-compat "^3.0.4" +react-virtualized-auto-sizer@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca" + integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ== -react@^16.0.0, react@^16.12.0, react@^16.13.1: +react-window@^1.8.6: + version "1.8.6" + resolved "https://registry.npmjs.org/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112" + integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg== + dependencies: + "@babel/runtime" "^7.0.0" + memoize-one ">=3.1.1 <6" + +react@^16.12.0, react@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== @@ -26974,6 +27269,11 @@ style-loader@^3.3.1: resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== +style-mod@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz#97e7c2d68b592975f2ca7a63d0dd6fcacfe35a01" + integrity sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw== + style-to-object@0.3.0, style-to-object@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" @@ -26994,6 +27294,17 @@ stylis@^4.0.6: resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.7.tgz#412a90c28079417f3d27c028035095e4232d2904" integrity sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA== +subscriptions-transport-ws@^0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz#baf88f050cba51d52afe781de5e81b3c31f89883" + integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0 || ^6.0.0 || ^7.0.0" + subscriptions-transport-ws@^0.9.18, subscriptions-transport-ws@^0.9.19: version "0.9.19" resolved "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" @@ -27244,6 +27555,14 @@ sync-fetch@0.3.0: buffer "^5.7.0" node-fetch "^2.6.1" +sync-fetch@0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.3.1.tgz#62aa82c4b4d43afd6906bfd7b5f92056458509f0" + integrity sha512-xj5qiCDap/03kpci5a+qc5wSJjc8ZSixgG2EUmH1B8Ea2sfWclQA7eH40hiHPCtkCn6MCk4Wb+dqcXdCy2PP3g== + dependencies: + buffer "^5.7.0" + node-fetch "^2.6.1" + table@^6.0.9: version "6.7.1" resolved "https://registry.npmjs.org/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" @@ -27517,11 +27836,6 @@ testcontainers@^7.23.0: ssh-remote-port-forward "^1.0.4" tar-fs "^2.1.1" -text-encoding-utf-8@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - text-extensions@^1.0.0: version "1.9.0" resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" @@ -27791,6 +28105,11 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + "traverse@>=0.3.0 <0.4": version "0.3.9" resolved "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" @@ -28239,6 +28558,11 @@ underscore@^1.12.1, underscore@^1.9.1: resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== +undici@^4.9.3: + version "4.11.0" + resolved "https://registry.npmjs.org/undici/-/undici-4.11.0.tgz#41fb4f944704d77e1c9fb472d40d2dbece64ccf2" + integrity sha512-gofXRqAdm81rzaZgPbMf98qvrNGd3ptJ26+mCcF3EXoC817p//MtL8XcDpTvHUXxdW27rAM2jvTae+KyAchorw== + unfetch@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" @@ -28497,7 +28821,7 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unixify@1.0.0: +unixify@1.0.0, unixify@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA= @@ -28844,6 +29168,11 @@ validator@^8.0.0: resolved "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== +value-or-promise@1.0.11: + version "1.0.11" + resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== + value-or-promise@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.6.tgz#218aa4794aa2ee24dcf48a29aba4413ed584747f" @@ -28957,6 +29286,11 @@ w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" +w3c-keyname@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b" + integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw== + w3c-xmlserializer@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" @@ -29049,6 +29383,11 @@ web-streams-polyfill@4.0.0-beta.1: resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.1.tgz#3b19b9817374b7cee06d374ba7eeb3aeb80e8c95" integrity sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" @@ -29249,11 +29588,6 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-fetch@^3.4.1: version "3.4.1" resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" @@ -29264,6 +29598,14 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^8.0.0, whatwg-url@^8.4.0: version "8.4.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" @@ -29519,6 +29861,11 @@ ws@7.4.6: resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.3.0: + version "8.3.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d" + integrity sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw== + "ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.2.3, ws@^7.3.1: version "7.5.0" resolved "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691"