diff --git a/.changeset/calm-scissors-jam.md b/.changeset/calm-scissors-jam.md deleted file mode 100644 index c815670fd0..0000000000 --- a/.changeset/calm-scissors-jam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add support for Github Enterprise in GitHubOrgReaderProcessor so you can properly ingest users of a GHE organization. diff --git a/.changeset/cost-insights-tasty-years-laugh.md b/.changeset/cost-insights-tasty-years-laugh.md deleted file mode 100644 index 3728514fb1..0000000000 --- a/.changeset/cost-insights-tasty-years-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -pin all projects selection to the top of menu list diff --git a/.changeset/curvy-dodos-fry.md b/.changeset/curvy-dodos-fry.md deleted file mode 100644 index 80ab333e38..0000000000 --- a/.changeset/curvy-dodos-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Break the refresh loop into several smaller transactions diff --git a/.changeset/dirty-melons-retire.md b/.changeset/dirty-melons-retire.md deleted file mode 100644 index 2b92b44678..0000000000 --- a/.changeset/dirty-melons-retire.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Introduce a `profile` section for group entities that can optional include a -`displayName`, `email` and `picture`. diff --git a/.changeset/dirty-wolves-wink.md b/.changeset/dirty-wolves-wink.md deleted file mode 100644 index 77f1a62aff..0000000000 --- a/.changeset/dirty-wolves-wink.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Support `profile` of groups including `displayName`, `email`, and `picture` in -`LdapOrgReaderProcessor`. The source fields for them can be configured in the -`ldapOrg` provider. diff --git a/.changeset/early-dots-drive.md b/.changeset/early-dots-drive.md deleted file mode 100644 index 7a5eedec78..0000000000 --- a/.changeset/early-dots-drive.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Ensure a name is always displayed for user entities in the org plugin. This can happen when there is no profile -displayName provided (e.g. a GitHub user that has not added a name to their profile) diff --git a/.changeset/friendly-carpets-repeat.md b/.changeset/friendly-carpets-repeat.md deleted file mode 100644 index 7fb0d2f6eb..0000000000 --- a/.changeset/friendly-carpets-repeat.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -'@backstage/techdocs-common': minor -'@backstage/plugin-techdocs': minor -'@backstage/plugin-techdocs-backend': minor ---- - -_Breaking changes_ - -1. Added option to use Google Cloud Storage as a choice to store the static generated files for TechDocs. - It can be configured using `techdocs.publisher.type` option in `app-config.yaml`. - Step-by-step guide to configure GCS is available here https://backstage.io/docs/features/techdocs/using-cloud-storage - Set `techdocs.publisher.type` to `'local'` if you want to continue using local filesystem to store TechDocs files. - -2. `techdocs.builder` is now required and can be set to `'local'` or `'external'`. (Set it to `'local'` for now, since CI/CD build - workflow for TechDocs will be available soon (in few weeks)). - If builder is set to 'local' and you open a TechDocs page, `techdocs-backend` will try to generate the docs, publish to storage and - show the generated docs afterwords. - If builder is set to `'external'`, `techdocs-backend` will only fetch the docs and will NOT try to generate and publish. In this case of `'external'`, - we assume that docs are being built in the CI/CD pipeline of the repository. - TechDocs will not assume a default value for `techdocs.builder`. It is better to explicitly define it in the `app-config.yaml`. - -3. When configuring TechDocs in your backend, there is a difference in how a new publisher is created. - -``` ---- const publisher = new LocalPublish(logger, discovery); -+++ const publisher = Publisher.fromConfig(config, logger, discovery); -``` - -Based on the config `techdocs.publisher.type`, the publisher could be either Local publisher or Google Cloud Storage publisher. - -4. `techdocs.storageUrl` is now a required config. Should be `http://localhost:7000/api/techdocs/static/docs` in most setups. - -5. Parts of `@backstage/plugin-techdocs-backend` have been moved to a new package `@backstage/techdocs-common` to generate docs. Also to publish docs - to-and-fro between TechDocs and a storage (either local or external). However, a Backstage app does NOT need to import the `techdocs-common` package - - app should only import `@backstage/plugin-techdocs` and `@backstage/plugin-techdocs-backend`. - -_Patch changes_ - -1. See all of TechDocs config options and its documentation https://backstage.io/docs/features/techdocs/configuration - -2. Logic about serving static files and metadata retrieval have been abstracted away from the router in `techdocs-backend` to the instance of publisher. - -3. Removed Material UI Spinner from TechDocs header. Spinners cause unnecessary UX distraction. - Case 1 (when docs are built and are to be served): Spinners appear for a split second before the name of site shows up. This unnecessarily distracts eyes because spinners increase the size of the Header. A dot (.) would do fine. Definitely more can be done. - Case 2 (when docs are being generated): There is already a linear progress bar (which is recommended in Storybook). diff --git a/.changeset/friendly-olives-breathe.md b/.changeset/friendly-olives-breathe.md deleted file mode 100644 index 9dce3b9709..0000000000 --- a/.changeset/friendly-olives-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Added configuration schema for the commonly used properties diff --git a/.changeset/giant-rice-jump.md b/.changeset/giant-rice-jump.md new file mode 100644 index 0000000000..20a574176e --- /dev/null +++ b/.changeset/giant-rice-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-api': patch +--- + +Fix for GitHub and SAML auth not properly updating session state when already logged in. diff --git a/.changeset/gorgeous-scissors-jog.md b/.changeset/gorgeous-scissors-jog.md deleted file mode 100644 index 3f192808c1..0000000000 --- a/.changeset/gorgeous-scissors-jog.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core': patch -'@backstage/plugin-org': patch ---- - -Add a `` component to `@backstage/core`. diff --git a/.changeset/groups_profile.png b/.changeset/groups_profile.png deleted file mode 100644 index 417faaa4af..0000000000 Binary files a/.changeset/groups_profile.png and /dev/null differ diff --git a/.changeset/grumpy-elephants-press.md b/.changeset/grumpy-elephants-press.md deleted file mode 100644 index d85d36e609..0000000000 --- a/.changeset/grumpy-elephants-press.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/integration': patch ---- - -Implement readTree on BitBucketUrlReader and getBitbucketDownloadUrl diff --git a/.changeset/heavy-ducks-raise.md b/.changeset/heavy-ducks-raise.md deleted file mode 100644 index 71a16da512..0000000000 --- a/.changeset/heavy-ducks-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Ignore relations when comparing entities. This stops the refresh loop from rewriting entities over and over. diff --git a/.changeset/little-lemons-hope.md b/.changeset/little-lemons-hope.md new file mode 100644 index 0000000000..e2a7f747d6 --- /dev/null +++ b/.changeset/little-lemons-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +GitLab preparer uses the right token (primarily the same one as the publisher, falling back to the integrations token) diff --git a/.changeset/nice-trains-punch.md b/.changeset/nice-trains-punch.md deleted file mode 100644 index 71225ac97c..0000000000 --- a/.changeset/nice-trains-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-pagerduty': patch ---- - -Supporting Timezones diff --git a/.changeset/odd-mugs-build.md b/.changeset/odd-mugs-build.md deleted file mode 100644 index bf95d23410..0000000000 --- a/.changeset/odd-mugs-build.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Support `profile` of groups including `displayName` and `picture` in -`GithubOrgReaderProcessor`. Fixes the import of `description` for groups. diff --git a/.changeset/orange-dancers-occur.md b/.changeset/orange-dancers-occur.md new file mode 100644 index 0000000000..0283ffb634 --- /dev/null +++ b/.changeset/orange-dancers-occur.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': minor +--- + +Add search plugin to default template for CLI created apps diff --git a/.changeset/purple-cycles-switch.md b/.changeset/purple-cycles-switch.md deleted file mode 100644 index c7594e4254..0000000000 --- a/.changeset/purple-cycles-switch.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Write relations directly as part of batch add / update of entities. - -Slight change of the `CommonDatabase` contract: - -## `addEntity` removed - -This method was unused by the core, and rendered unnecessary when `addEntities` -exists. - -If you were a user of `addEntity`, please call `addEntities` instead, with an -array of one element. - -## `DbEntityRequest` has a new field `relations` - -This is the structure that is passed to `addEntities` and `updateEntity`. It -used to be the case that you needed to call `setRelations` separately, but now -this instead happens directly when you call `addEntities` or `updateEntity`. - -If you were using `addEntities` or `updateEntity` directly, please adapt your -code to add the `relations` array to each request. If you were calling -`setRelations` separately next to these methods, you no longer need to do so, -after adding the relations to the `DbEntityRequest`s. diff --git a/.changeset/quiet-pants-happen.md b/.changeset/quiet-pants-happen.md new file mode 100644 index 0000000000..165e3ae12c --- /dev/null +++ b/.changeset/quiet-pants-happen.md @@ -0,0 +1,7 @@ +--- +'@backstage/core': patch +'@backstage/test-utils': patch +'@backstage/plugin-graphiql': patch +--- + +Update to use new plugin extension API diff --git a/.changeset/rare-peas-accept.md b/.changeset/rare-peas-accept.md deleted file mode 100644 index 74597dda11..0000000000 --- a/.changeset/rare-peas-accept.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Batch the writing of statuses after refreshes. This reduced the runtime on sqlite from 16s to 0.2s, and on pg from 60s to 1s on my machine, for the huge LDAP set. diff --git a/.changeset/rotten-pandas-draw.md b/.changeset/rotten-pandas-draw.md deleted file mode 100644 index 85b3feeaec..0000000000 --- a/.changeset/rotten-pandas-draw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add index to foreign key columns. Postgres (and others) do not do this on the "source" side of a foreign key relation, which was what led to the slowness on large datasets. The full LDAP dataset ingestion now takes two minutes, which is not optimal yet but still a huge improvement over before when it basically never finished :) diff --git a/.changeset/shiny-grapes-tan.md b/.changeset/shiny-grapes-tan.md deleted file mode 100644 index b7361bb970..0000000000 --- a/.changeset/shiny-grapes-tan.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Validate that integration config contains a valid host diff --git a/.changeset/short-dancers-explode.md b/.changeset/short-dancers-explode.md new file mode 100644 index 0000000000..56fee63fe7 --- /dev/null +++ b/.changeset/short-dancers-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-api': patch +--- + +Introduce new plugin extension API diff --git a/.changeset/six-mugs-camp.md b/.changeset/six-mugs-camp.md deleted file mode 100644 index 373edd340a..0000000000 --- a/.changeset/six-mugs-camp.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -In the techdocs-backend plugin (`packages/backend/src/plugins/techdocs.ts`), create a publisher using - -``` - const publisher = Publisher.fromConfig(config, logger, discovery); -``` - -instead of - -``` - const publisher = new LocalPublish(logger, discovery); -``` - -An instance of `publisher` can either be a local filesystem publisher or a Google Cloud Storage publisher. - -Read more about the configs here https://backstage.io/docs/features/techdocs/configuration -(You will also have to update `techdocs.storage.type` to `local` or `googleGcs`. And `techdocs.builder` to either `local` or `external`.) diff --git a/.changeset/wet-garlics-shave.md b/.changeset/slimy-penguins-sing.md similarity index 61% rename from .changeset/wet-garlics-shave.md rename to .changeset/slimy-penguins-sing.md index 86b42541eb..62b27a1ce6 100644 --- a/.changeset/wet-garlics-shave.md +++ b/.changeset/slimy-penguins-sing.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-sentry': patch +'@backstage/plugin-catalog-backend': patch --- Added configuration schema for the commonly used properties diff --git a/.changeset/swift-sheep-ring.md b/.changeset/swift-sheep-ring.md deleted file mode 100644 index f4cf92c29d..0000000000 --- a/.changeset/swift-sheep-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Re-enable symlink resolution during bundling, and switch to using a resolve plugin for external linked packages. diff --git a/.changeset/tender-coats-unite.md b/.changeset/tender-coats-unite.md deleted file mode 100644 index 018660bcfa..0000000000 --- a/.changeset/tender-coats-unite.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Display the new `profile` fields (`displayName`, `email`, and `picture`) for -groups on the `GroupProfileCard`. - -![Groups Profile Section](./groups_profile.png) - -This also resolves some cases where `profile` fields are missing for users or -groups and for example falls back to displaying the entity name. Adds additional test data to the ACME Corp dataset. diff --git a/.changeset/warm-moose-applaud.md b/.changeset/warm-moose-applaud.md new file mode 100644 index 0000000000..70ae20711a --- /dev/null +++ b/.changeset/warm-moose-applaud.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Clearer error message when preparer or publisher type can't be determined. diff --git a/.changeset/weak-sloths-prove.md b/.changeset/weak-sloths-prove.md deleted file mode 100644 index bfecb385c8..0000000000 --- a/.changeset/weak-sloths-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added configuration schema for the commonly used properties diff --git a/.changeset/witty-scissors-divide.md b/.changeset/witty-scissors-divide.md deleted file mode 100644 index f288088ef2..0000000000 --- a/.changeset/witty-scissors-divide.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Support `profile` of groups including `displayName` and `email` in -`MicrosoftGraphOrgReaderProcessor`. Importing `picture` doesn't work yet, as -the Microsoft Graph API does not expose them correctly. diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 3b7e2a9e2d..b4be37c057 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -1,4 +1,5 @@ abc +adamdmharvey andrewthauer Apdex api @@ -35,6 +36,7 @@ Codecov codehilite Codehilite codeowners +composable config Config configmaps @@ -48,6 +50,7 @@ deadnaming destructured dev devs +dhenneke discoverability Discoverability dls @@ -56,6 +59,8 @@ Dockerfile Dockerize dockerode Docusaurus +Dominik +dtuite dzolotusky eg Ek @@ -79,6 +84,7 @@ graphviz Gustavsson Hackathons haproxy +Henneke heroku Heroku horizontalpodautoscalers @@ -140,14 +146,17 @@ Oldsberg onboarding Onboarding pagerduty +parallelization Patrik Phoen plantuml Pomaceous postgres +postpack pre prebaked preconfigured +prepack Preprarer Prerequisities productional @@ -185,6 +194,7 @@ Serverless Sinon smartsymobls Snyk +sourcemaps sparklines Spotifiers spotify @@ -218,6 +228,9 @@ toolsets tooltip tooltips touchpoints +transpiled +transpilation +Tuite ui untracked upvote diff --git a/ADOPTERS.md b/ADOPTERS.md index 304512ee7e..3d5914d97b 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -1,6 +1,6 @@ | Organization | Contact | Description of Use | | -------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | -| [Spotify](https://www.spotify.com) | [@stefanalund](https://github.com/stefanalund) | Main interface towards all of Spotify's infrastructure and technical documentation. | +| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. | | [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. | | [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. | | [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up | diff --git a/OWNERS.md b/OWNERS.md index 8e5002fc0a..f1649c50b8 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -22,3 +22,6 @@ People that have made significant contributions to the project and earned write - Andrew Thauer - Wealthsimple (GitHub: [andrewthauer](https://github.com/andrewthauer)) - Oliver Sand - SDA SE (GitHub: [Fox32](https://github.com/Fox32)) +- David Tuite - Roadie (GitHub: [dtuite](https://github.com/dtuite)) +- Adam Harvey - DXC Technology (GitHub: [adamdmharvey](https://github.com/adamdmharvey)) +- Dominik Henneke - SDA SE (GitHub: [dhenneke](https://github.com/dhenneke)) diff --git a/docs/cli/commands.md b/docs/cli/commands.md new file mode 100644 index 0000000000..c505bf8ae7 --- /dev/null +++ b/docs/cli/commands.md @@ -0,0 +1,559 @@ +--- +id: commands +title: Commands +description: Descriptions of all commands available in the CLI. +--- + +This page lists all commands provided by the Backstage CLI, what they're for, +and where to use them. + +The documentation for each command begins with specifying its scope, this +indicates where the command should be used by selecting from the following list: + +- `app` - A frontend app package, such as `packages/app`. +- `backend` - A backend package, such as `packages/backend`. +- `frontend-plugin` - A frontend plugin package. +- `backend-plugin` - A backend plugin package. +- `root` - The monorepo root. +- `any` - Any kind of package, but not the repo root. + +## help + +This command displays a help summary or detailed help screens for each command. +Below is a cleaned up output of `yarn backstage-cli --help`. + +```text +app:build Build an app for a production release +app:diff Diff an existing app with the creation template +app:serve Serve an app for local development + +backend:build Build a backend plugin +backend:build-image Bundles the package into a docker image +backend:dev Start local development server with HMR for the backend + +plugin:build Build a plugin +plugin:diff Diff an existing plugin with the creation template +plugin:serve Serves the dev/ folder of a plugin + +build Build a package for publishing +build-workspace Builds a temporary dist workspace from the provided packages +lint Lint a package +test Run tests, forwarding args to Jest, defaulting to watch mode +clean Delete cache directories + +create-plugin Creates a new plugin in the current repository +remove-plugin Removes plugin in the current repository + +config:print Print the app configuration for the current package +config:check Validate that the given configuration loads and matches schema + +versions:bump Bump Backstage packages to the latest versions +versions:check Check Backstage package versioning + +prepack Prepares a package for packaging before publishing +postpack Restores the changes made by the prepack command + +help [command] display help for command +``` + +## app:build + +Scope: `app` + +Builds a bundle of static content from the app, which can then be served via any +static web server such as `nginx`, or via the +[`app-backend`](https://www.npmjs.com/package/@backstage/plugin-app-backend) +plugin directly from a Backstage backend instance. + +The command also reads and injects static configuration into the bundle. It is +important to note that when deploying using your own static content hosting +solution, this will be the final configuration used in the frontend unless you +for example hook in configuration loading from the backend. When using the +`nginx` based Dockerfile in this repo along with its included run script, +`APP_CONFIG_` environment variables will be injected into the frontend, and when +serving using the `app-backend` plugin, the configuration is completely injected +from the backend and the configuration at the time of calling this command will +not be used. + +Note that even when injecting configuration at runtime, it is not possible to +change the base path of the app. For example, if you at build time have +`app.baseUrl` set to `http://dev-app.com/my-app`, you can change that to +`https://prod-app.com/my-app`, but not to `https://prod-app.com`, as that would +change the path. + +During the build, the following variables are set: + +```java +process.env.NODE_ENV = 'production'; +process.env.BUILD_INFO = { + cliVersion: '0.4.0', // The version of the CLI package + gitVersion: 'v0.4.0-86-ge54815618', // output of `git describe --always` + packageVersion: '1.0.5', // The version of the app package itself + timestamp: 1678900000000, // Date.now() when the build started + commit: 'e548156182a973ed4b459e18533afc22c85ffff8', // output of `git rev-parse HEAD` +}; +``` + +Some CI environments do not properly report correct resource limits, potentially +leading to errors such as `ENOMEM` during compilation. If you run into this +issue you can limit the parallelization of the build process by setting the +environment variable `BACKSTAGE_CLI_BUILD_PARALLEL`, which is forwarded to the +[`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#parallel). +You can set it to `false` or `1` to completely disable parallelization, but +usually a low value such as `2` is enough. + +```text +Usage: backstage-cli app:build + +Options: + --stats Write bundle stats to output directory + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## app:diff + +Scope: `app` + +Diff an existing app with the template used in `@backstage/create-app`. This +will verify that your app package has not diverged from the template, and can be +useful to run after updating the version of `@backstage/cli` in your app. + +This command is experimental and may be removed in the future. + +```text +Usage: backstage-cli app:diff + +Options: + --check Fail if changes are required + --yes Apply all changes + -h, --help display help for command +``` + +## app:serve + +Scope: `app` + +Serve an app for local development. This starts up a local development server, +using a bundling configuration that is quite similar to that of the `app:build` +command, but with development features such as React Hot Module Replacement, +faster sourcemaps, no minification, etc. + +The static configuration is injected into the frontend, but it does not support +watching, meaning that changes in for example `app-config.yaml` are not +reflected until the serve process is restarted. + +During the build, the following variables are set: + +```java +process.env.NODE_ENV = 'development'; +process.env.BUILD_INFO = { /* See app:build */ }; +``` + +The server listening configuration is controlled through the static +configuration. The `app.baseUrl` determines the listening host and port, as well +as whether HTTPS is used or not. It is also possible to override the listening +host and port if needed by setting `app.listen.host` and `app.listen.port`. + +```text +Usage: backstage-cli app:serve [options] + +Options: + --check Enable type checking and linting + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## backend:build + +Scope: `backend`, `backend-plugin` + +This builds a backend package for publishing and use in production. The build +output is written to `dist/`. Be sure to list any additional file that the +package depends on at runtime in the `"files"` field inside `package.json`, a +common example being the `migrations` directory. + +```text +Usage: backstage-cli backend:build [options] + +Options: + -h, --help display help for command +``` + +## backend:build-image + +Scope: `backend` + +Builds a Docker image of the backend package, forwarding all unknown options to +`docker image build`. For example: + +```bash +yarn backstage-cli backend:build-image --build --tag my-backend-image +``` + +The image is built using the backend package along with all of its local package +dependencies. It expects to find a `Dockerfile` at the root of the backend +package, which will be used during the build. + +The Dockerfile is **NOT** executed within the package or repo itself. Because +the packages in the repo itself are configured for development instead of +production use, the final Docker build happens in a separate temporary +directory, to which the backend package and dependencies have been copied. Only +files listed within the `"files"` field within each package's `package.json` are +copied over, along with the root `package.json`, `yarn.lock`, and any +`app-config.*.yaml` files. + +During the build a `skeleton.tar` file is created and put at the repo root. This +file contains the `package.json` of each included package, which together with +the root `package.json` and `yarn.lock` can be used to run a cached +`yarn install` before the full production builds of all the packages are copied +over, providing a significant speedup if Docker build layer caching available. + +This command is experimental and we hope to be able to replace it with one that +is less integrated directly with Docker, and also supports multi-stage Docker +builds. It is possible to replicate most of what this command does by manually +building each package, and then use the `build-workspace` to create the +temporary workspace, and finally copy over any additional files to the workspace +and execute the Docker build within it. + +```text +Usage: backstage-cli backend:build-image [options] + +Options: + --build Build packages before packing them into the image + --backstage-cli-help display help for command +``` + +## backend:dev + +Scope: `backend`, `backend-plugin` + +Starts a backend package in development mode, with watch mode enabled for all +local dependencies. + +```text +Usage: backstage-cli backend:dev [options] + +Options: + --check Enable type checking and linting + --inspect Enable debugger + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## create-plugin + +Scope: `root` + +Creates a new plugin within the repository. This command is typically wrapped up +in the root `package.json` to be executed with `yarn create-plugin`, using +options that are appropriate for the organization that owns the app repo. A +recommended scope for internal packages is `@internal`. + +```text +Usage: backstage-cli create-plugin [options] + +Options: + --backend Create plugin with the backend dependencies as default + --scope <scope> npm scope + --npm-registry <URL> npm registry URL + --no-private Public npm package + -h, --help display help for command +``` + +## remove-plugin + +Scope: `root` + +A utility to remove a plugin from a repo, essentially undoing everything that +was done by `create-plugin`. + +This is primarily intended as a utility for manual tests and end to end testing +scripts. + +```text +Usage: backstage-cli remove-plugin [options] + +Options: + -h, --help display help for command +``` + +## plugin:build + +Scope: `frontend-plugin` + +Build a frontend plugin for publishing to a package registry. There is no need +to run this command during development or even in CI unless the package is being +published. The `app:bundle` command does not use the output for this command +when bundling local package dependencies. + +The output is written to a `dist/` folder. It also outputs type declarations for +the plugin, and therefore requires `yarn tsc` to have been run first. The input +type declarations are expected to be found within `dist-types/` at the root of +the monorepo. + +```text +Usage: backstage-cli plugin:build [options] + +Options: + -h, --help display help for command +``` + +## plugin:serve + +Scope: `frontend-plugin` + +Serves a frontend plugin by itself for isolated development. The serve task +itself is essentially identical to `app:serve`, but the entrypoint is instead +set to the `dev/` folder within the plugin. + +The `dev/` folder typically contains a small wrapper script that hooks up any +necessary mock APIs or other things that are needed for the plugin to function. +The `@backstage/dev-utils` package provides utilities to that end. + +```text +Usage: backstage-cli plugin:serve [options] + +Options: + --check Enable type checking and linting + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## plugin:diff + +Scope: `frontend-plugin` + +Compares a frontend plugin to the `create-plugin` template, making sure that it +hasn't diverged from the template and recommending updates when it has. A good +practice is to run this command after updating the version of the CLI in a +project. + +```text +Usage: backstage-cli plugin:diff [options] + +Options: + --check Fail if changes are required + --yes Apply all changes + -h, --help display help for command +``` + +## build + +Scope: `any` + +Build a single package for publishing, just like the `plugin:build` and +`backend:build` commands. This command is intended for standalone packages that +aren't plugins, and for example support building of isomorphic packages for +usage in both the frontend and backend. + +For frontend packages you'll want to include `esm` output, and for backend +packages `cjs`. Whether to include `types` depends on if you need type +declarations for the package, and also requires `yarn tsc` to have been run +first. + +```text +Usage: backstage-cli build [options] + +Options: + --outputs <formats> List of formats to output [types,cjs,esm] + -h, --help display help for command +``` + +## lint + +Scope: `any` + +Lint a package. In addition to the default `eslint` behavior, this command will +include TypeScript files, treat warnings as errors, and default to linting the +entire directory if no specific files are listed. + +```text +Usage: backstage-cli lint [options] + +Options: + --format <format> Lint report output format (default: "eslint-formatter-friendly") + --fix Attempt to automatically fix violations + -h, --help display help for command +``` + +## test + +Scope: `any` + +Run tests, forwarding all unknown options to Jest, and defaulting to watch mode. +When executing the tests, `process.env.NODE_ENV` will be set to `"test"`. + +This command uses a default Jest configuration that is included in the CLI, +which is set up with similar goals for speed, scale, and working within a +monorepo. The configuration sets the `src` as the root directory, enforces the +`.test.` infix for tests, and uses `src/setupTests.ts` as the test setup +location. + +If needed, the configuration can be extended using a `"jest"` field in +`package.json`, both within the target package and the monorepo root, with +configuration in the target package taking precedence. Refer to the +[Jest configuration documentation](https://jestjs.io/docs/en/configuration) for +a full list of configuration options. + +In addition to the Jest configuration there's an optional `transformModules` +option, which is an array of module names to include in transformations. +Normally modules inside `node_modules` are not transformed, but there are cases +were published packages are not transpiled far enough to be usable by Jest, in +which case you need to enable transform of them. + +Another way to override the Jest configuration is to place a `jest.config.js` or +`jest.config.ts` file in the package root. As opposed to the `package.json` way +of overriding config, this completely removes the base config, and so you need +to set it up from scratch. + +```text +Usage: backstage-cli test [options] + +Options: + --backstage-cli-help display help for command +``` + +## config:print + +Scope: `root` + +Print the static configuration, defaulting to reading `app-config.yaml` in the +repo root, using schema collected from all local packages in the repo. + +For example, to validate that a given configuration value is visible in the +frontend when building the `my-app` package, you can use the following: + +```bash +yarn backstage-cli config:print --frontend --package my-app +``` + +```text +Usage: backstage-cli config:print [options] + +Options: + --package <name> Only load config schema that applies to the given package + --frontend Print only the frontend configuration + --with-secrets Include secrets in the printed configuration + --format <format> Format to print the configuration in, either json or yaml [yaml] + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## config:check + +Scope: `root` + +Validate that static configuration loads and matches schema, defaulting to +reading `app-config.yaml` in the repo root and using schema collected from all +local packages in the repo. + +```text +Usage: backstage-cli config:check [options] + +Options: + --package <name> Only load config schema that applies to the given package + --config <path> Config files to load instead of app-config.yaml (default: []) + -h, --help display help for command +``` + +## versions:bump + +Scope: `root` + +Bump all `@backstage` packages to the latest versions. This checks for updates +in the package registry, and will update entries both in `yarn.lock` and +`package.json` files when necessary. + +```text +Usage: backstage-cli versions:bump [options] + +Options: + -h, --help display help for command +``` + +## versions:check + +Scope: `root` + +Validate `@backstage` dependencies within the repo, making sure that there are +no duplicates of packages that might lead to breakages. For example, +`@backstage/core` must not be loaded in twice, so having two different versions +of it installed will cause this command to exit with an error. + +By supplying the `--fix` flag the command will attempt to fix any conflict that +can be resolved by editing `yarn.lock`, but will not attempt to search for +remote updates or modify any `package.json` files. + +```text +Usage: backstage-cli versions:check [options] + +Options: + --fix Fix any auto-fixable versioning problems + -h, --help display help for command +``` + +## prepack + +Scope: `any` + +This command should be added as `scripts.prepack` in all packages. It enables +packaging- and publish-time overrides for fields inside `packages.json`. + +The checked in version of all packages in a Backstage monorepo are tailored for +local development, and as such `main` and similar fields inside `package.json` +point to development source, i.e. `src/index.ts`. Using this when publishing +would lead to a broken package, since `src/` is not included in the published +package and we instead need to point to files in the `dist/` directory. This +command allows for those fields to be rewritten when needed, and does so by +copying all fields within `publishConfig` to the top-level of each +`package.json`, skipping `access`, `registry`, and `tag`. + +The need for this command may be removed in the future, as this exact method of +overriding fields for publishing is already supported by some package managers. + +```text +Usage: backstage-cli prepack [options] + +Options: + -h, --help display help for command +``` + +## postpack + +Scope: `any` + +This should be added as `scripts.postpack` in all packages. It restores +`package.json` to what it looked like before calling the `prepack` command. + +```text +Usage: backstage-cli postpack [options] + +Options: + -h, --help display help for command +``` + +## clean + +Scope: `any` + +Remove cache and output directories. + +```text +Usage: backstage-cli clean [options] + +Options: + -h, --help display help for command +``` + +## build-workspace + +Scope: `any`, `root` + +Builds a mirror of the workspace using the packaged production version of each +package. This essentially calls `yarn pack` in each included package and unpacks +the resulting archive in the target `workspace-dir`. + +```text +Usage: backstage-cli build-workspace [options] <workspace-dir> +``` diff --git a/docs/cli/index.md b/docs/cli/index.md new file mode 100644 index 0000000000..1b2e01be62 --- /dev/null +++ b/docs/cli/index.md @@ -0,0 +1,108 @@ +--- +id: index +title: Overview +description: Overview of the Backstage CLI +--- + +## Summary + +Backstage provides an opinionated set of tooling for both frontend and backend +development. It is delivered through the +[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) package and +executed either directly through `yarn backstage-cli ` or within +`package.json` scripts. When creating an app using +[`@backstage/create-app`](https://www.npmjs.com/package/@backstage/create-app) +it contains package scripts for executing the most common commands. + +Under the hood the CLI uses [Webpack](https://webpack.js.org/) for bundling, +[Rollup](https://rollupjs.org/) for building packages, +[Jest](https://jestjs.io/) for testing, and [eslint](https://eslint.org/) for +linting. It also includes custom tooling for working within Backstage apps, for +example for keeping the app up to date and verifying static configuration. + +For a full list of CLI commands, see the [commands](./commands.md) page. + +## Introduction + +A goal of Backstage is to provide a delightful developer experience in and +around the project. Creating new apps and plugins should be simple, iteration +speed should be fast, and the overhead of maintaining custom tooling should be +minimal. As a part of accomplishing this goal, Backstage provides its own set of +opinionated tooling, delivered primarily through the +[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) package. + +The `@backstage/cli` package provides a single executable script, +`backstage-cli`, which you can run directly with `yarn` or within a script in +`package.json`. If you have a Backstage app set up, you can try out the +following command to print the top-level help page of the CLI: + +```text +yarn backstage-cli --help +``` + +If you are familiar with [`create-react-app`](https://create-react-app.dev/) you +may recognize the pattern of bundling tooling up as a CLI, as it uses a package +called [`react-scripts`](https://www.npmjs.com/package/react-scripts) to bring +most of the functionality into the created project. The Backstage equivalent of +`create-react-app` is +[`@backstage/create-app`](https://www.npmjs.com/package/@backstage/create-app), +and the equivalent of `react-scripts` is `@backstage/cli`. There are however a +couple of key differences between the two. Most notably, Backstage apps are +monorepos and the CLI is tailored for that environment. It provides tooling both +for bundling and developing full end-user apps, but also for developing, +building and publishing individual packages within the monorepo, as well as +tooling that is more unique to Backstage, such as commands for working with +static configuration. + +## Opinionated Tooling + +The Backstage CLI is highly opinionated in what tools are used and how they are +configured. It is tailored for development in large TypeScript monorepos with +hundreds of separate packages, but with the ability to have edits anywhere in +the codebase reflected within a few seconds. The build output is also optimized +for this setup, and aims to provide an excellent user experience with fast page +load times in modern browsers, rather than a wide range of support. + +While the Backstage tooling is opinionated in how to develop and build packages, +it is also possible to use your own tooling either partially or fully. For +example, the CLI provides a command for building a plugin package for +publishing, but the output is a quite standard combination of transpiled +JavaScript and TypeScript type declarations. The usage of the command from the +CLI can therefore easily be replaced with other tools if necessary. + +Just like `react-scripts`, the Backstage CLI does not provide many hooks for +overriding or customizing the build process. This is to allow for evolution of +the CLI without having to take a wide API surface into account. This allows us +to quickly iterate and improve the tooling, as well as to more easily keep +dependencies up to date. + +## Opinions & Goals + +In no particular order, this is a list of opinions and goals that guide the +design and development of the Backstage CLI: + +- All you need for development is `yarn start`, there should be no need to + manually build packages or run other separate tasks. +- Development experience comes first. The toolchain is optimized for keeping + development smooth, rather than making it easy to for example build and + publish packages. +- Type checking and linting is left for text editors and Continuous Integration. + Most text editors provide tooling for these checks, and running them a second + time during compilation slows down iteration speed and consumes more system + resources. +- Backstage is run in modern browsers. We keep transpilation lightweight and + rely on modern technologies such as HTTP/2 to optimize frontend speed. + +## Glossary + +- **Package** - A package in the Node.js ecosystem, often published to a package + registry such as [NPM](https://www.npmjs.com/). +- **Monorepo** - A project layout that consists of multiple packages within a + single project, where packages are able to have local dependencies on each + other. Often enabled through tooling such as [lerna](https://lerna.js.org/) + and [yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/) +- **Local Package** - One of the packages within a monorepo. These package may + or may not also be published to a package registry. +- **Bundle** - A collection of the deployment artifacts. The output of the + bundling process, which brings a collection of packages into a single + collection of deployment artifacts. diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index e17c5ca36e..763acd2261 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -444,21 +444,6 @@ Apart from being a string, the software catalog leaves the format of this field open to implementers to choose. Most commonly, it is set to the ID or email of a group of people in an organizational structure. -### `spec.implementsApis` [optional] - -**NOTE**: This field was marked for deprecation on Nov 25nd, 2020. It will be -removed entirely from the model on Dec 14th, 2020 in the repository and will not -be present in released packages following the next release after that. Please -update your code to not consume this field before the removal date. - -Links APIs that are implemented by the component, e.g. `artist-api`. This field -is optional. - -The software catalog expects a list of one or more strings that references the -names of other entities of the `kind` `API`. - -This field has the same behavior as `spec.providesApis`. - ### `spec.providesApis` [optional] Links APIs that are provided by the component, e.g. `artist-api`. This field is diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md index 16131a1ded..50cadc7b27 100644 --- a/docs/features/techdocs/README.md +++ b/docs/features/techdocs/README.md @@ -96,26 +96,38 @@ Build a widget (plugin) framework so that contributors can easily contribute features to TechDocs - that others can use. And, also, so that we can easily migrate Spotify's existing TechDocs features to open source. -## Structure +## Platforms Supported -- [Getting Started] -- [Concepts] -- [Creating and Publishing Documentation] -- [FAQ] +See [TechDocs Architecture](architecture.md) to get an overview of where these +providers are used. + +| Source Code Hosting Provider | Support Status | +| ---------------------------- | -------------- | +| GitHub | Yes ✅ | +| GitHub Enterprise | Yes ✅ | +| BitBucket | Yes ✅ | +| Azure DevOps | Yes ✅ | +| GitLab | Yes ✅ | +| GitLab Enterprise | Yes ✅ | + +| File Storage Provider | Support Status | Track status | +| --------------------------------- | -------------- | ----------------------------------------------------------- | +| Local Filesystem of Backstage app | Yes ✅ | | +| Google Cloud Storage (GCS) | Yes ✅ | | +| Amazon Web Services (AWS) S3 | No ❌ | [#3714](https://github.com/backstage/backstage/issues/3714) | +| Azure Storage | No ❌ | | + +[Reach out to us](#feedback) if you want to request more platforms. ## Tech Stack -| Stack | Location | -| ------------------------------------------- | -------------------------------------------------------- | -| Frontend | [`@backstage/plugin-techdocs`][techdocs/frontend] | -| Backend | [`@backstage/plugin-techdocs-backend`][techdocs/backend] | -| Docker Container (for generating doc sites) | [`techdocs-container`][techdocs/container] | -| CLI (for local development) | [`@techdocs/cli`][techdocs/cli] | +| Stack | Location | +| ----------------------------------------------- | -------------------------------------------------------- | +| Frontend Plugin | [`@backstage/plugin-techdocs`][techdocs/frontend] | +| Backend Plugin | [`@backstage/plugin-techdocs-backend`][techdocs/backend] | +| CLI (for local development and generating docs) | [`@techdocs/cli`][techdocs/cli] | +| Docker Container (for generating docs) | [`techdocs-container`][techdocs/container] | -[getting started]: getting-started.md -[concepts]: concepts.md -[creating and publishing documentation]: creating-and-publishing.md -[faq]: FAQ.md 'Frequently asked questions' [techdocs/frontend]: https://github.com/backstage/backstage/blob/master/plugins/techdocs [techdocs/backend]: @@ -131,3 +143,6 @@ https://docs.google.com/forms/d/e/1FAIpQLSdn5Vn3MQhCdyYRuW8cMzZkMQF0bFxXYN168gZR This is to gather inputs from you (the Backstage community) which will help us best serve TechDocs adopters and existing users. Your inputs will shape our roadmap and we will share it in the open. + +For any other general queries, reach out to us in the `#docs-like-code` channel +of our [Discord chatroom](https://github.com/backstage/backstage#community). diff --git a/docs/features/techdocs/concepts.md b/docs/features/techdocs/concepts.md index 1675c64288..26254a7e12 100644 --- a/docs/features/techdocs/concepts.md +++ b/docs/features/techdocs/concepts.md @@ -8,15 +8,45 @@ Spotify's docs-like-code solution in Backstage This page describes concepts that are introduced with Spotify's docs-like-code solution in Backstage. -### TechDocs Core Plugin +## Generating TechDocs Steps -The TechDocs Core Plugin is an [MkDocs](https://www.mkdocs.org/) plugin created -as a wrapper around multiple MkDocs plugins and Python Markdown extensions to -standardize the configuration of MkDocs used for TechDocs. +### TechDocs Preparer -[TechDocs Core](https://github.com/backstage/mkdocs-techdocs-core) +Preparing is the first step of generating documentation for an entity. It +fetches the source markdown files from the source code hosting provider (GitHub, +GitLab, etc.) and passes the files to the generator for next steps. -### TechDocs container +There are two kinds of preparers available - + +1. Common Git Preparer - Uses `git clone` on any repository url. +2. Url Reader - Uses source code hosting provider's API to download files. + (Faster and recommended) + +### TechDocs Generator + +Generating is the second step after preparing the markdown source files. This +step either runs the TechDocs container (defined below) or runs `mkdocs` CLI to +generate static HTML files and its assets. + +### TechDocs Publisher + +Publishing is the third and final step after preparing and generating docs. +TechDocs Publisher uploads the generated files to a storage. + +The `techdocs-backend` plugin currently comes with two publishers - Google Cloud +Storage and Local Filesystem. You can configure them in your Backstage app. +[See here](./configuration.md). + +A TechDocs publisher is responsible for two things (two-way communication +between `techdocs-backend` and the storage) + +1. Publish generated static files to a storage (Configured by + `techdocs.builder`) +2. Read files from the storage when users visit a TechDocs site + +[TechDocs Backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend) + +## TechDocs Container The TechDocs container is a Docker container available at [DockerHub](https://hub.docker.com/r/spotify/techdocs). It builds static HTML @@ -25,16 +55,15 @@ MkDocs. [TechDocs Container](https://github.com/backstage/techdocs-container) -### TechDocs publisher +## TechDocs Core Plugin -The `techdocs-backend` plugin currently comes with one publisher - -`LocalPublish`. +The TechDocs Core Plugin is an [MkDocs](https://www.mkdocs.org/) plugin created +as a wrapper around multiple MkDocs plugins and Python Markdown extensions to +standardize the configuration of MkDocs used for TechDocs. -[TechDocs Backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend) +[TechDocs Core](https://github.com/backstage/mkdocs-techdocs-core) -More standalone publishers will come in the near future... - -### TechDocs CLI +## TechDocs CLI The TechDocs CLI was created to make it easy to write, generate and preview documentation for publishing. Currently it mostly acts as a wrapper around the @@ -43,7 +72,7 @@ container. [TechDocs CLI](https://github.com/backstage/techdocs-cli) -### TechDocs Reader +## TechDocs Reader Documentation generated by TechDocs is generated as static HTML sites. The TechDocs Reader was therefore created to be able to integrate pre-generated HTML @@ -55,7 +84,7 @@ TechDocs widgets for a customized full-featured TechDocs experience. [TechDocs Reader](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/reader/README.md) -### Transformers +## Transformers Transformers are different pieces of functionality used inside the TechDocs Reader. The reason why transformers were introduced was to provide a way to diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index e51c6a122e..c82bc8b95b 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -1,7 +1,7 @@ --- id: getting-started title: Getting Started -description: Getting Started Guidelines +description: Getting Started Documentation --- TechDocs functions as a plugin to Backstage, so you will need to use Backstage @@ -10,50 +10,156 @@ to use TechDocs. If you haven't setup Backstage already, start [here](../../getting-started/index.md). -## Installing TechDocs +> If you used `npx @backstage/create-app`, TechDocs may already be present. +> +> You should skip to [`Setting the Configuration`](#setting-the-configuration) +> below. -TechDocs is provided with the Backstage application by default. If you want to -set up TechDocs manually, keep following the instructions below. - -### Adding the package +## Adding TechDocs frontend plugin The first step is to add the TechDocs plugin to your Backstage application. -Navigate to your new Backstage application folder: - -```bash -cd hello-world/ -``` - -Then navigate to your `packages/app` folder to install TechDocs: +Navigate to your new Backstage application directory. And then to your +`packages/app` directory, and install the `@backstage/plugin-techdocs` package. ```bash +cd my-backstage-app/ cd packages/app yarn add @backstage/plugin-techdocs ``` -After a short while, the TechDocs plugin should be successfully installed. +Once the package has been installed, you need to import the plugin in your app. -Next, you need to set up some basic configuration. Enter the following command: - -```bash -yarn install -``` - -Add this to `packages/app/src/plugins.ts`: +Add the following to `packages/app/src/plugins.ts`: ```typescript export { plugin as TechDocs } from '@backstage/plugin-techdocs'; ``` -### Setting the configuration +Now let us embed the TechDocs router in our main Backstage frontend router. In +`packages/app/src/App.tsx`, import the TechDocs router and add the following to +`AppRoutes`: -TechDocs allows for configuration of the docs storage URL through your -`app-config.yaml` file. We provide two different values to be configured, -`requestUrl` and `storageUrl`. The `requestUrl` is what the reader will request -its data from, and `storageUrl` is where the backend can find the stored -documentation. +```tsx +import { Router as DocsRouter } from '@backstage/plugin-techdocs'; -The default storage and request URLs: +// ... + +const AppRoutes = () => { + + // ... other plugin routes + } /> + ; +}; +``` + +That's it! But now, we need the TechDocs Backend plugin for the frontend to +work. + +## Adding TechDocs Backend plugin + +Navigate to `packages/backend` of your Backstage app, and install the +`@backstage/plugin-techdocs-backend` package. + +```bash +cd my-backstage-app/ +cd packages/backend +yarn add @backstage/plugin-techdocs-backend +``` + +Create a file called `techdocs.ts` inside `packages/backend/src/plugins/` and +add the following + +```typescript +import { + createRouter, + DirectoryPreparer, + Preparers, + Generators, + TechdocsGenerator, + CommonGitPreparer, + UrlPreparer, + Publisher, +} from '@backstage/plugin-techdocs-backend'; +import { PluginEnvironment } from '../types'; +import Docker from 'dockerode'; + +export default async function createPlugin({ + logger, + config, + discovery, + reader, +}: PluginEnvironment) { + // Preparers are responsible for fetching source files for documentation. + const preparers = new Preparers(); + + const directoryPreparer = new DirectoryPreparer(logger); + preparers.register('dir', directoryPreparer); + + const commonGitPreparer = new CommonGitPreparer(logger); + preparers.register('github', commonGitPreparer); + preparers.register('gitlab', commonGitPreparer); + preparers.register('azure/api', commonGitPreparer); + + const urlPreparer = new UrlPreparer(reader, logger); + preparers.register('url', urlPreparer); + + // Generators are used for generating documentation sites. + const generators = new Generators(); + const techdocsGenerator = new TechdocsGenerator(logger, config); + generators.register('techdocs', techdocsGenerator); + + // Publishers are used for + // 1. Publishing generated files to storage + // 2. Fetching files from storage and passing them to TechDocs frontend. + const publisher = Publisher.fromConfig(config, logger, discovery); + + // Docker client used by the generators. + const dockerClient = new Docker(); + + return await createRouter({ + preparers, + generators, + publisher, + dockerClient, + logger, + config, + discovery, + }); +} +``` + +You may need to install the `dockerode` package. But you may already have it in +your backend since [Scaffolder plugin](../software-templates/index.md) also uses +it. + +See [Concepts](concepts.md) and [TechDocs Architecture](architecture.md) to +learn more about how preparers, generators and publishers work. + +Final step is to import the techdocs backend plugin in Backstage app backend. +Add the following to your `packages/backend/src/index.ts`: + +```typescript +import techdocs from './plugins/techdocs'; + +// .... main should already be present. +async function main() { + // ... other backend plugin envs + const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + + // ... other backend plugin routes + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); +} +``` + +That's it! TechDocs frontend and backend have now been added to your Backstage +app. Now let us tweak some configurations to suit your needs. + +## Setting the configuration + +**See [TechDocs Configuration Options](configuration.md) for complete +configuration reference.** + +### Setting TechDocs URLs ```yaml techdocs: @@ -61,22 +167,59 @@ techdocs: requestUrl: http://localhost:7000/api/techdocs/ ``` -If you want `techdocs-backend` to manage building and publishing, you want -`requestUrl` to point to the default value (or wherever `techdocs-backend` is -hosted). `storageUrl` should be where your publisher publishes your docs. Using -the default `LocalPublish` that is the default value. +`requestUrl` is used by TechDocs frontend plugin to discover techdocs-backend +endpoints, and the `storageUrl` is another endpoint in `techdocs-backend` which +acts as a middleware between TechDocs and the storage (where the static +generated docs site are stored). These default values should mostly work for +you. These options will soon be optional to set. -If you have a setup where you are not using `techdocs-backend` for managing -building and publishing of your documentation, you want to change the -`requestUrl` to point to your storage. In this case `storageUrl` is not -required. +### Should TechDocs Backend generate docs? -### Disable Docker in Docker situation (Optional) +```yaml +techdocs: + storageUrl: http://localhost:7000/api/techdocs/static/docs + requestUrl: http://localhost:7000/api/techdocs/ + builder: 'local' +``` -The TechDocs backend plugin runs a docker container with mkdocs installed to +Set `techdocs.builder` to `'local'` if you want your TechDocs Backend to be +responsible for generating documentation sites. If set to `'external'`, +Backstage will assume that the sites are being generated on each entity's CI/CD +pipeline, and are being stored in a storage somewhere. + +When `techdocs.builder` is set to `'external'`, TechDocs becomes more or less a +read-only experience where it serves static files from a storage containing all +the generated documentation. Read more in the "Basic" and "Recommended" setup of +TechDocs [here](architecture.md) + +### Choosing storage (publisher) + +TechDocs needs to know where to store generated documentation sites and where to +fetch the sites from. This is managed by a +[Publisher](./concepts.md#techdocs-publisher). Examples: Google Cloud Storage, +Amazon S3, or local filesystem of Backstage server. + +It is okay to use the local filesystem in a "Basic" setup when you are trying +out Backstage for the first time. Using Cloud Storage is documented +[here](./using-cloud-storage.md). + +```yaml +techdocs: + storageUrl: http://localhost:7000/api/techdocs/static/docs + requestUrl: http://localhost:7000/api/techdocs/ + builder: 'local' + publisher: + type: 'local' +``` + +### Disabling Docker in Docker situation (Optional) + +You can skip this if your `techdocs.builder` is set to `'external'`. + +The TechDocs Backend plugin runs a docker container with mkdocs installed to generate the frontend of the docs from source files (Markdown). If you are deploying Backstage using Docker, this will mean that your Backstage Docker -container will try to run another Docker container for TechDocs backend. +container will try to run another Docker container for TechDocs Backend. To avoid this problem, we have a configuration available. You can set a value in your `app-config.yaml` that tells the techdocs generator if it should run the @@ -108,23 +251,13 @@ the dependencies. For example, we want `Markdown` version to be You can also explicitly install `Markdown==3.2.2` after installing all other Python packages. -## Run Backstage locally +## Running Backstage locally -Change folder to `/packages/backend` and run the -following command: +Start the frontend and the backend app by +[running backstage locally](../../getting-started/running-backstage-locally.md). -```bash -yarn start -``` - -Open a new command line window. Change directory to your Backstage application -root and run the following command: - -```bash -yarn start -``` - -Open your browser at [http://localhost:3000/docs/](http://localhost:3000/docs/). +Open your browser at [http://localhost:3000/docs/](http://localhost:3000/docs/) +to see all your documentation sites. ## Additional reading diff --git a/docs/features/techdocs/using-cloud-storage.md b/docs/features/techdocs/using-cloud-storage.md index 55352b6c00..c7b5ec9a9f 100644 --- a/docs/features/techdocs/using-cloud-storage.md +++ b/docs/features/techdocs/using-cloud-storage.md @@ -40,7 +40,7 @@ techdocs: publisher: type: 'googleGcs' googleGcs: - projectId: 'gcp-project-id + projectId: 'gcp-project-id' ``` **3. Service account API key** @@ -76,7 +76,7 @@ Create a dedicated bucket for TechDocs sites. techdocs-backend will publish documentation to this bucket. TechDocs will fetch files from here to serve documentation in Backstage. -Set the name of the bucket to `techdocs.publisher +Set the name of the bucket to `techdocs.publisher.googleGcs.bucketName`. ```yaml techdocs: diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index 71612cc5e4..b0c031689d 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -47,55 +47,42 @@ guidelines to get started. ### Ongoing work 🚧 -- **[Plugins for managing micro services end-2-end](https://github.com/backstage/backstage/milestone/14)** - Out of the box Backstage will ship with a set of plugins (Overview, CI, API - and Docs) that will demonstrate how a user can manage a micro service and - follow a change all the way out in production. Completing this work will make - it much easier to see how a plugin can be built that integrates with the - Backstage Service Catalog. +- **[Platform stabilization](https://github.com/backstage/backstage/milestone/19)** - + Stabilize the core of Backstage, including its core features, so that the + platform can be depended on for production use. After this, plugins will + require little-to-no maintenance. -- **[Users and teams](https://github.com/backstage/backstage/issues/1807)** - Ownership is a central concept in Backstage. It should be easy to import your - existing organizational data, such as users and groups/teams, into Backstage. - A user the logs into Backstage should see software components owned by the - team(s) they are in. +- **[Kubernetes plugin for service owners](https://github.com/backstage/backstage/issues/2857)** - + Improve native support for Kubernetes, making it easier for service owners to + see and manage their services running in K8s, regardless if that's locally, in + AWS, GCS, Azure, or elsewhere. -- **[Backstage platform is stable](https://github.com/backstage/backstage/milestone/19)** - - The platform APIs and features are stable and can be depended on for - production use. After this plugins will require little to no maintenance. +- **Global search** - Extend the basic search functionality currently available + in the Backstage Service Catalog to become a global search experience. -* **[Improved Kubernetes plugin](https://github.com/backstage/backstage/issues/2857)** - - Native support for Kubernetes, making it easier for developers to see and - manage their services running in k8s. - -- Further improvements to platform documentation. Examples include a Golden Path - for plugin development. +- **[Software Templates V2](https://github.com/backstage/backstage/issues/2771)** - + Expand the templates to make the steps more composable by adding the ability + to add more steps for custom logic, including webhooks and using authorization + from integrations. ### Future work 🔮 -- **Deploy a product demo at `demo.backstage.io`** - Deploy a typical Backstage - deployment available publicly so that people can click around and get a feel - for the product without having to install anything. +- **Golden Path for Plugin Development** - Create an easy, standardized way for + developers to build plugins that will encourage contributions and lead to a + richer ecosystem for everyone. -- **[Global search](https://github.com/backstage/backstage/issues/1499)** - - Extend the basic search available in the Backstage Service Catalog with a - global search experience. Long term this search solution should be extensible, - making it possible for you add custom search results. - -- **[[TechDocs V.2] Stabilization release](https://github.com/backstage/backstage/milestone/17)** - - Platform stability and compatibility improvements. - -- **Additional auth providers** - Backstage should work for most (all!) auth - solutions. Since Backstage can be used by companies regardless of what cloud - (or on prem) you are using we are especially keen to get auth support for - [AWS](https://github.com/backstage/backstage/issues/290), - [Azure](https://github.com/backstage/backstage/issues/348) and others. - -- **[Initial GraphQL API](https://github.com/backstage/backstage/milestone/13)** - - A GraphQL API will open up the rich metadata provided by Backstage in a single +- **[GraphQL API](https://github.com/backstage/backstage/milestone/13)** - A + GraphQL API will open up the rich metadata provided by Backstage in a single query. Plugins can easily query this API as well as extend the model where needed. +- **Inter-Plugin Communication** - **[Under consideration]** Establish more + clearly defined patterns for plugins to communicate. + +- **Improved Access Control** - **[Under consideration]** Provide finer grained + access controls and management for better control of the platform user + experience. + ### Plugins Building and maintaining [plugins](https://backstage.io/plugins) is the work of @@ -110,8 +97,17 @@ Are you missing a plugin for your favorite tool? Please [suggest a new one](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). Chances are that someone will jump in and help build it. +### Community Initiatives 🧑‍🤝‍🧑 (Coming soon) + +- **Backstage Monthly Meetup** - A space for the community to come together to + share and learn about the latest happenings in Backstage. + +- **Backstage Hackathons** - Open to everyone in our Backstage community, a + celebration of you, the project and building awesome things together + ### Completed milestones ✅ +- [Deploy a product demo at `demo.backstage.io`](https://demo.backstage.io) - [Kubernetes plugin - v1](https://github.com/backstage/backstage/tree/master/plugins/kubernetes) - [Helm charts](https://github.com/backstage/backstage/tree/master/contrib/chart/backstage) - [Backstage Design System 💅](https://backstage.io/blog/2020/09/30/backstage-design-system) diff --git a/docs/support/project-structure.md b/docs/support/project-structure.md index 190259841c..bbba127c9a 100644 --- a/docs/support/project-structure.md +++ b/docs/support/project-structure.md @@ -169,11 +169,19 @@ are separated out into their own folder, see further down. packages, publish them, created a new app, and the run it. CI uses this for e2e-tests. +- [`integration/`](https://github.com/backstage/backstage/tree/master/packages/integration) - + Common functionalities of integrations like GitHub, GitLab, etc. + - [`storybook/`](https://github.com/backstage/backstage/tree/master/packages/storybook) - This folder contains only the storybook config. Stories are within the core package. The Backstage Storybook is found [here](https://backstage.io/storybook) +- [`techdocs-common/`](https://github.com/backstage/backstage/tree/master/packages/techdocs-common) - + Common functionalities for TechDocs, to be shared between + [techdocs-backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend) + plugin and [techdocs-cli](https://github.com/backstage/techdocs-cli). + - [`test-utils-core/`](https://github.com/backstage/backstage/tree/master/packages/test-utils-core) - [`test-utils/`](https://github.com/backstage/backstage/tree/master/packages/test-utils) diff --git a/microsite/data/plugins/pager-duty.yaml b/microsite/data/plugins/pager-duty.yaml new file mode 100644 index 0000000000..e8a0a1b0d9 --- /dev/null +++ b/microsite/data/plugins/pager-duty.yaml @@ -0,0 +1,13 @@ +--- +title: PageDuty +author: Spotify +authorUrl: https://github.com/spotify +category: Monitoring +description: PagerDuty offers a simple way to identify any active incidents for an entity and the escalation policy. +documentation: https://github.com/backstage/backstage/tree/master/plugins/pagerduty +iconUrl: https://avatars2.githubusercontent.com/u/766800?s=200&v=4 +npmPackageName: '@backstage/plugin-pagerduty' +tags: + - monitoring + - errors + - alerting diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 91112dd3b3..b31f0ccdf3 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -34,6 +34,7 @@ ] } ], + "CLI": ["cli/index", "cli/commands"], "Core Features": [ { "type": "subcategory", diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css index c07285ed8c..46b2aa3470 100644 --- a/microsite/static/css/custom.css +++ b/microsite/static/css/custom.css @@ -48,6 +48,14 @@ h6 { color: $textColor; } +h2:hover .hash-link { + opacity: 1; +} + +.hash-link { + fill: white; +} + /* body elements */ p, ul, diff --git a/package.json b/package.json index b89ac76d9e..caf19b0311 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,9 @@ "version": "1.0.0", "devDependencies": { "@changesets/cli": "^2.11.0", + "@octokit/openapi-types": "^2.0.0", "@spotify/eslint-config-oss": "^1.0.1", - "@spotify/prettier-config": "^8.0.0", + "@spotify/prettier-config": "^9.0.0", "command-exists": "^1.2.9", "concurrently": "^5.2.0", "fs-extra": "^9.0.0", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 03958c831c..799895ef56 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,44 @@ # example-app +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c0fac6163] +- Updated dependencies [48c305e69] +- Updated dependencies [c911061b7] +- Updated dependencies [ab805860a] +- Updated dependencies [dae4f3983] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [f3e75508d] +- Updated dependencies [3b50f833d] +- Updated dependencies [c36a01b4c] +- Updated dependencies [c5297baeb] +- Updated dependencies [ac3560b42] +- Updated dependencies [962d1ad66] + - @backstage/plugin-org@0.3.2 + - @backstage/plugin-cost-insights@0.5.2 + - @backstage/catalog-model@0.6.0 + - @backstage/plugin-techdocs@0.5.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog-import@0.3.2 + - @backstage/plugin-pagerduty@0.2.3 + - @backstage/cli@0.4.2 + - @backstage/plugin-sentry@0.3.1 + - @backstage/plugin-api-docs@0.4.1 + - @backstage/plugin-catalog@0.2.7 + - @backstage/plugin-circleci@0.2.5 + - @backstage/plugin-cloudbuild@0.2.5 + - @backstage/plugin-github-actions@0.2.5 + - @backstage/plugin-jenkins@0.3.4 + - @backstage/plugin-kubernetes@0.3.3 + - @backstage/plugin-lighthouse@0.2.6 + - @backstage/plugin-register-component@0.2.5 + - @backstage/plugin-rollbar@0.2.7 + - @backstage/plugin-scaffolder@0.3.4 + - @backstage/plugin-search@0.2.4 + ## 0.2.6 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 9d05ae659a..63710a5c28 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,36 +1,36 @@ { "name": "example-app", - "version": "0.2.6", + "version": "0.2.7", "private": true, "bundled": true, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/cli": "^0.4.1", - "@backstage/core": "^0.4.0", - "@backstage/plugin-api-docs": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", - "@backstage/plugin-catalog-import": "^0.3.1", - "@backstage/plugin-circleci": "^0.2.4", - "@backstage/plugin-cloudbuild": "^0.2.4", - "@backstage/plugin-cost-insights": "^0.5.0", + "@backstage/catalog-model": "^0.6.0", + "@backstage/cli": "^0.4.2", + "@backstage/core": "^0.4.1", + "@backstage/plugin-api-docs": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", + "@backstage/plugin-catalog-import": "^0.3.2", + "@backstage/plugin-circleci": "^0.2.5", + "@backstage/plugin-cloudbuild": "^0.2.5", + "@backstage/plugin-cost-insights": "^0.5.2", "@backstage/plugin-explore": "^0.2.2", "@backstage/plugin-gcp-projects": "^0.2.2", - "@backstage/plugin-github-actions": "^0.2.4", + "@backstage/plugin-github-actions": "^0.2.5", "@backstage/plugin-gitops-profiles": "^0.2.2", "@backstage/plugin-graphiql": "^0.2.2", - "@backstage/plugin-org": "^0.3.1", - "@backstage/plugin-jenkins": "^0.3.3", - "@backstage/plugin-kubernetes": "^0.3.2", - "@backstage/plugin-lighthouse": "^0.2.5", + "@backstage/plugin-org": "^0.3.2", + "@backstage/plugin-jenkins": "^0.3.4", + "@backstage/plugin-kubernetes": "^0.3.3", + "@backstage/plugin-lighthouse": "^0.2.6", "@backstage/plugin-newrelic": "^0.2.2", - "@backstage/plugin-pagerduty": "0.2.2", - "@backstage/plugin-register-component": "^0.2.4", - "@backstage/plugin-rollbar": "^0.2.6", - "@backstage/plugin-scaffolder": "^0.3.3", - "@backstage/plugin-sentry": "^0.3.0", - "@backstage/plugin-search": "^0.2.3", + "@backstage/plugin-pagerduty": "0.2.3", + "@backstage/plugin-register-component": "^0.2.5", + "@backstage/plugin-rollbar": "^0.2.7", + "@backstage/plugin-scaffolder": "^0.3.4", + "@backstage/plugin-sentry": "^0.3.1", + "@backstage/plugin-search": "^0.2.4", "@backstage/plugin-tech-radar": "^0.3.1", - "@backstage/plugin-techdocs": "^0.4.0", + "@backstage/plugin-techdocs": "^0.5.0", "@backstage/plugin-user-settings": "^0.2.3", "@backstage/plugin-welcome": "^0.2.3", "@backstage/test-utils": "^0.1.5", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 627b5d19aa..a58bf45f9c 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -29,7 +29,7 @@ import { hot } from 'react-hot-loader/root'; import { providers } from './identityProviders'; import { Router as CatalogRouter } from '@backstage/plugin-catalog'; import { Router as DocsRouter } from '@backstage/plugin-techdocs'; -import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql'; +import { GraphiQLPage } from '@backstage/plugin-graphiql'; import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse'; import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component'; @@ -81,7 +81,7 @@ const AppRoutes = () => ( path="/tech-radar" element={} /> - } /> + } /> } /> { - const createConfig = (data: any) => - ConfigReader.fromConfigs([ - { - context: '', - data, - }, - ]); - const defaultConfigOptions = { backend: { database: { @@ -42,7 +34,7 @@ describe('SingleConnectionDatabaseManager', () => { }, }, }; - const defaultConfig = () => createConfig(defaultConfigOptions); + const defaultConfig = () => new ConfigReader(defaultConfigOptions); // This is similar to the ts-jest `mocked` helper. const mocked = (f: Function) => f as jest.Mock; diff --git a/packages/backend-common/src/database/connection.test.ts b/packages/backend-common/src/database/connection.test.ts index de0b0e40dc..9810ff9bef 100644 --- a/packages/backend-common/src/database/connection.test.ts +++ b/packages/backend-common/src/database/connection.test.ts @@ -18,19 +18,11 @@ import { ConfigReader } from '@backstage/config'; import { createDatabaseClient } from './connection'; describe('database connection', () => { - const createConfig = (data: any) => - ConfigReader.fromConfigs([ - { - context: '', - data, - }, - ]); - describe('createDatabaseClient', () => { it('returns a postgres connection', () => { expect( createDatabaseClient( - createConfig({ + new ConfigReader({ client: 'pg', connection: { host: 'acme', @@ -46,7 +38,7 @@ describe('database connection', () => { it('returns an sqlite connection', () => { expect( createDatabaseClient( - createConfig({ + new ConfigReader({ client: 'sqlite3', connection: ':memory:', }), @@ -57,7 +49,7 @@ describe('database connection', () => { it('tries to create a mysql connection as a passthrough', () => { expect(() => createDatabaseClient( - createConfig({ + new ConfigReader({ client: 'mysql', connection: { host: '127.0.0.1', @@ -73,7 +65,7 @@ describe('database connection', () => { it('accepts overrides', () => { expect( createDatabaseClient( - createConfig({ + new ConfigReader({ client: 'pg', connection: { host: 'acme', @@ -94,7 +86,7 @@ describe('database connection', () => { it('throws an error without a client', () => { expect(() => createDatabaseClient( - createConfig({ + new ConfigReader({ connection: '', }), ), @@ -104,7 +96,7 @@ describe('database connection', () => { it('throws an error without a connection', () => { expect(() => createDatabaseClient( - createConfig({ + new ConfigReader({ client: 'pg', }), ), diff --git a/packages/backend-common/src/database/postgres.test.ts b/packages/backend-common/src/database/postgres.test.ts index 8d139e4481..59c135f309 100644 --- a/packages/backend-common/src/database/postgres.test.ts +++ b/packages/backend-common/src/database/postgres.test.ts @@ -34,15 +34,7 @@ describe('postgres', () => { 'postgresql://foo:bar@acme:5432/foodb'; const createConfig = (connection: any): Config => - ConfigReader.fromConfigs([ - { - context: '', - data: { - client: 'pg', - connection, - }, - }, - ]); + new ConfigReader({ client: 'pg', connection }); describe('buildPgDatabaseConfig', () => { it('builds a postgres config', () => { diff --git a/packages/backend-common/src/database/sqlite3.test.ts b/packages/backend-common/src/database/sqlite3.test.ts index a3ab331c2d..a6b8e5d84d 100644 --- a/packages/backend-common/src/database/sqlite3.test.ts +++ b/packages/backend-common/src/database/sqlite3.test.ts @@ -22,15 +22,7 @@ import { describe('sqlite3', () => { const createConfig = (connection: any) => - ConfigReader.fromConfigs([ - { - context: '', - data: { - client: 'sqlite3', - connection, - }, - }, - ]); + new ConfigReader({ client: 'sqlite3', connection }); describe('buildSqliteDatabaseConfig', () => { it('buidls a string connection', () => { diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 3a76c0631b..6cc5e30dbd 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -14,12 +14,14 @@ * limitations under the License. */ +import { ConfigReader } from '@backstage/config'; +import { msw } from '@backstage/test-utils'; +import fs from 'fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { ConfigReader } from '@backstage/config'; +import path from 'path'; import { getVoidLogger } from '../logging'; import { GitlabUrlReader } from './GitlabUrlReader'; -import { msw } from '@backstage/test-utils'; import { ReadTreeResponseFactory } from './tree'; const logger = getVoidLogger(); @@ -30,105 +32,207 @@ const treeResponseFactory = ReadTreeResponseFactory.create({ describe('GitlabUrlReader', () => { const worker = setupServer(); - msw.setupDefaultHandlers(worker); - beforeEach(() => { - worker.use( - rest.get('*/api/v4/projects/:name', (_, res, ctx) => - res(ctx.status(200), ctx.json({ id: 12345 })), - ), - rest.get('*', (req, res, ctx) => - res( - ctx.status(200), - ctx.json({ - url: req.url.toString(), - headers: req.headers.getAllHeaders(), - }), + describe('implementation', () => { + beforeEach(() => { + worker.use( + rest.get('*/api/v4/projects/:name', (_, res, ctx) => + res(ctx.status(200), ctx.json({ id: 12345 })), ), - ), - ); - }); - - const createConfig = (token?: string) => - new ConfigReader( - { - integrations: { gitlab: [{ host: 'gitlab.com', token }] }, - }, - 'test-config', - ); - - it.each([ - // Project URLs - { - url: - 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - config: createConfig(), - response: expect.objectContaining({ - url: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - headers: expect.objectContaining({ - 'private-token': '', - }), - }), - }, - { - url: - 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - config: createConfig('0123456789'), - response: expect.objectContaining({ - url: - 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - headers: expect.objectContaining({ - 'private-token': '0123456789', - }), - }), - }, - { - url: - 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path/to/file.yaml', // Repo not in subgroup - config: createConfig(), - response: expect.objectContaining({ - url: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }), - }, - - // Raw URLs - { - url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', - config: createConfig(), - response: expect.objectContaining({ - url: 'https://gitlab.example.com/a/b/raw/master/c.yaml', - }), - }, - ])('should handle happy path %#', async ({ url, config, response }) => { - const [{ reader }] = GitlabUrlReader.factory({ - config, - logger, - treeResponseFactory, + rest.get('*', (req, res, ctx) => + res( + ctx.status(200), + ctx.json({ + url: req.url.toString(), + headers: req.headers.getAllHeaders(), + }), + ), + ), + ); }); - const data = await reader.read(url); - const res = await JSON.parse(data.toString('utf-8')); - expect(res).toEqual(response); - }); + const createConfig = (token?: string) => + new ConfigReader( + { + integrations: { gitlab: [{ host: 'gitlab.com', token }] }, + }, + 'test-config', + ); - it.each([ - { - url: '', - config: createConfig(''), - error: - "Invalid type in config for key 'integrations.gitlab[0].token' in 'test-config', got empty-string, wanted string", - }, - ])('should handle error path %#', async ({ url, config, error }) => { - await expect(async () => { + it.each([ + // Project URLs + { + url: + 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', + config: createConfig(), + response: expect.objectContaining({ + url: + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + headers: expect.objectContaining({ + 'private-token': '', + }), + }), + }, + { + url: + 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', + config: createConfig('0123456789'), + response: expect.objectContaining({ + url: + 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + headers: expect.objectContaining({ + 'private-token': '0123456789', + }), + }), + }, + { + url: + 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path/to/file.yaml', // Repo not in subgroup + config: createConfig(), + response: expect.objectContaining({ + url: + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + }), + }, + + // Raw URLs + { + url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', + config: createConfig(), + response: expect.objectContaining({ + url: 'https://gitlab.example.com/a/b/raw/master/c.yaml', + }), + }, + ])('should handle happy path %#', async ({ url, config, response }) => { const [{ reader }] = GitlabUrlReader.factory({ config, logger, treeResponseFactory, }); - await reader.read(url); - }).rejects.toThrow(error); + + const data = await reader.read(url); + const res = await JSON.parse(data.toString('utf-8')); + expect(res).toEqual(response); + }); + + it.each([ + { + url: '', + config: createConfig(''), + error: + "Invalid type in config for key 'integrations.gitlab[0].token' in 'test-config', got empty-string, wanted string", + }, + ])('should handle error path %#', async ({ url, config, error }) => { + await expect(async () => { + const [{ reader }] = GitlabUrlReader.factory({ + config, + logger, + treeResponseFactory, + }); + await reader.read(url); + }).rejects.toThrow(error); + }); + }); + + describe('readTree', () => { + const repoBuffer = fs.readFileSync( + path.resolve('src', 'reading', '__fixtures__', 'repo.zip'), + ); + + beforeEach(() => { + worker.use( + rest.get( + 'https://gitlab.com/backstage/mock/-/archive/repo/mock-repo.zip', + (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/zip'), + ctx.body(repoBuffer), + ), + ), + ); + }); + + it('returns the wanted files from an archive', async () => { + const processor = new GitlabUrlReader( + { host: 'gitlab.com' }, + { treeResponseFactory }, + ); + + const response = await processor.readTree( + 'https://gitlab.com/backstage/mock/tree/repo', + ); + + const files = await response.files(); + expect(files.length).toBe(2); + + const indexMarkdownFile = await files[0].content(); + const mkDocsFile = await files[1].content(); + + expect(mkDocsFile.toString()).toBe('site_name: Test\n'); + expect(indexMarkdownFile.toString()).toBe('# Test\n'); + }); + + it('returns the wanted files from hosted gitlab', async () => { + worker.use( + rest.get( + 'https://git.mycompany.com/backstage/mock/-/archive/repo/mock-repo.zip', + (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/zip'), + ctx.body(repoBuffer), + ), + ), + ); + + const processor = new GitlabUrlReader( + { host: 'git.mycompany.com' }, + { treeResponseFactory }, + ); + + const response = await processor.readTree( + 'https://git.mycompany.com/backstage/mock/tree/repo/docs', + ); + + const files = await response.files(); + + expect(files.length).toBe(1); + const indexMarkdownFile = await files[0].content(); + + expect(indexMarkdownFile.toString()).toBe('# Test\n'); + }); + + it('throws an error when branch is not specified', async () => { + const processor = new GitlabUrlReader( + { host: 'gitlab.com' }, + { treeResponseFactory }, + ); + + await expect( + processor.readTree('https://gitlab.com/backstage/mock'), + ).rejects.toThrow( + 'GitLab URL must contain a branch to be able to fetch its tree', + ); + }); + + it('returns the wanted files from an archive with a subpath', async () => { + const processor = new GitlabUrlReader( + { host: 'gitlab.com' }, + { treeResponseFactory }, + ); + + const response = await processor.readTree( + 'https://gitlab.com/backstage/mock/tree/repo/docs', + ); + + const files = await response.files(); + + expect(files.length).toBe(1); + const indexMarkdownFile = await files[0].content(); + + expect(indexMarkdownFile.toString()).toBe('# Test\n'); + }); }); }); diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index d6d1da5cbb..d51e8dc090 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -21,22 +21,37 @@ import { readGitLabIntegrationConfigs, } from '@backstage/integration'; import fetch from 'cross-fetch'; -import { NotFoundError } from '../errors'; -import { ReaderFactory, ReadTreeResponse, UrlReader } from './types'; +import { InputError, NotFoundError } from '../errors'; +import { ReadTreeResponseFactory } from './tree'; +import { + ReaderFactory, + ReadTreeOptions, + ReadTreeResponse, + UrlReader, +} from './types'; +import parseGitUri from 'git-url-parse'; +import { Readable } from 'stream'; export class GitlabUrlReader implements UrlReader { - static factory: ReaderFactory = ({ config }) => { + private readonly treeResponseFactory: ReadTreeResponseFactory; + + static factory: ReaderFactory = ({ config, treeResponseFactory }) => { const configs = readGitLabIntegrationConfigs( config.getOptionalConfigArray('integrations.gitlab') ?? [], ); return configs.map(options => { - const reader = new GitlabUrlReader(options); + const reader = new GitlabUrlReader(options, { treeResponseFactory }); const predicate = (url: URL) => url.host === options.host; return { reader, predicate }; }); }; - constructor(private readonly options: GitLabIntegrationConfig) {} + constructor( + private readonly options: GitLabIntegrationConfig, + deps: { treeResponseFactory: ReadTreeResponseFactory }, + ) { + this.treeResponseFactory = deps.treeResponseFactory; + } async read(url: string): Promise { const builtUrl = await getGitLabFileFetchUrl(url, this.options); @@ -59,8 +74,45 @@ export class GitlabUrlReader implements UrlReader { throw new Error(message); } - readTree(): Promise { - throw new Error('GitlabUrlReader does not implement readTree'); + async readTree( + url: string, + options?: ReadTreeOptions, + ): Promise { + const { + name: repoName, + ref, + protocol, + resource, + full_name, + filepath, + } = parseGitUri(url); + + if (!ref) { + throw new InputError( + 'GitLab URL must contain a branch to be able to fetch its tree', + ); + } + + const archive = `${protocol}://${resource}/${full_name}/-/archive/${ref}/${repoName}-${ref}.zip`; + const response = await fetch( + archive, + getGitLabRequestOptions(this.options), + ); + if (!response.ok) { + const msg = `Failed to read tree from ${url}, ${response.status} ${response.statusText}`; + if (response.status === 404) { + throw new NotFoundError(msg); + } + throw new Error(msg); + } + + const path = filepath ? `${repoName}-${ref}/${filepath}/` : ''; + + return this.treeResponseFactory.fromZipArchive({ + stream: (response.body as unknown) as Readable, + path, + filter: options?.filter, + }); } toString() { diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index 778e25f71c..46bf23beef 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -52,7 +52,7 @@ const DEFAULT_CSP = { 'frame-ancestors': ["'self'"], 'img-src': ["'self'", 'data:'], 'object-src': ["'none'"], - 'script-src': ["'self'"], + 'script-src': ["'self'", "'unsafe-eval'"], 'script-src-attr': ["'none'"], 'style-src': ["'self'", 'https:', "'unsafe-inline'"], 'upgrade-insecure-requests': [] as string[], diff --git a/packages/backend-common/src/service/lib/config.test.ts b/packages/backend-common/src/service/lib/config.test.ts index 8a35f147ca..75252357d6 100644 --- a/packages/backend-common/src/service/lib/config.test.ts +++ b/packages/backend-common/src/service/lib/config.test.ts @@ -20,9 +20,7 @@ import { readCspOptions } from './config'; describe('config', () => { describe('readCspOptions', () => { it('reads valid values', () => { - const config = ConfigReader.fromConfigs([ - { context: '', data: { csp: { key: ['value'] } } }, - ]); + const config = new ConfigReader({ csp: { key: ['value'] } }); expect(readCspOptions(config)).toEqual( expect.objectContaining({ key: ['value'], @@ -31,9 +29,7 @@ describe('config', () => { }); it('accepts false', () => { - const config = ConfigReader.fromConfigs([ - { context: '', data: { csp: { key: false } } }, - ]); + const config = new ConfigReader({ csp: { key: false } }); expect(readCspOptions(config)).toEqual( expect.objectContaining({ key: false, @@ -42,9 +38,7 @@ describe('config', () => { }); it('rejects invalid value types', () => { - const config = ConfigReader.fromConfigs([ - { context: '', data: { csp: { key: [4] } } }, - ]); + const config = new ConfigReader({ csp: { key: [4] } }); expect(() => readCspOptions(config)).toThrow(/wanted string-array/); }); }); diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index d0a8f4112a..3f053accfa 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,35 @@ # example-backend +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c6eeefa35] +- Updated dependencies [fb386b760] +- Updated dependencies [c911061b7] +- Updated dependencies [7c3ffc0cd] +- Updated dependencies [dae4f3983] +- Updated dependencies [7b15cc271] +- Updated dependencies [e7496dc3e] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [8dd0a906d] +- Updated dependencies [4eafdec4a] +- Updated dependencies [6b37c95bf] +- Updated dependencies [8c31c681c] +- Updated dependencies [7b98e7fee] +- Updated dependencies [ac3560b42] +- Updated dependencies [94c65a9d4] +- Updated dependencies [0097057ed] + - @backstage/plugin-catalog-backend@0.5.0 + - @backstage/catalog-model@0.6.0 + - @backstage/plugin-techdocs-backend@0.4.0 + - @backstage/plugin-auth-backend@0.2.7 + - @backstage/backend-common@0.4.1 + - @backstage/plugin-scaffolder-backend@0.3.5 + - example-app@0.2.7 + - @backstage/plugin-kubernetes-backend@0.2.3 + ## 0.2.6 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 74b459d691..718b008c7b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.6", + "version": "0.2.7", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,23 +27,23 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@backstage/plugin-app-backend": "^0.3.3", - "@backstage/plugin-auth-backend": "^0.2.6", - "@backstage/plugin-catalog-backend": "^0.4.0", + "@backstage/plugin-auth-backend": "^0.2.7", + "@backstage/plugin-catalog-backend": "^0.5.0", "@backstage/plugin-graphql-backend": "^0.1.4", - "@backstage/plugin-kubernetes-backend": "^0.2.2", + "@backstage/plugin-kubernetes-backend": "^0.2.3", "@backstage/plugin-proxy-backend": "^0.2.3", "@backstage/plugin-rollbar-backend": "^0.1.5", - "@backstage/plugin-scaffolder-backend": "^0.3.4", - "@backstage/plugin-techdocs-backend": "^0.3.2", + "@backstage/plugin-scaffolder-backend": "^0.3.5", + "@backstage/plugin-techdocs-backend": "^0.4.0", "@gitbeaker/node": "^25.2.0", "@octokit/rest": "^18.0.0", "azure-devops-node-api": "^10.1.1", "dockerode": "^3.2.1", - "example-app": "^0.2.6", + "example-app": "^0.2.7", "express": "^4.17.1", "express-promise-router": "^3.0.3", "knex": "^0.21.6", @@ -53,7 +53,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/backend/src/plugins/techdocs.ts b/packages/backend/src/plugins/techdocs.ts index 4720b2568e..4822de9c5c 100644 --- a/packages/backend/src/plugins/techdocs.ts +++ b/packages/backend/src/plugins/techdocs.ts @@ -32,10 +32,7 @@ export default async function createPlugin({ discovery, reader, }: PluginEnvironment) { - const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator(logger, config); - generators.register('techdocs', techdocsGenerator); - + // Preparers are responsible for fetching source files for documentation. const preparers = new Preparers(); const directoryPreparer = new DirectoryPreparer(logger); @@ -49,8 +46,17 @@ export default async function createPlugin({ const urlPreparer = new UrlPreparer(reader, logger); preparers.register('url', urlPreparer); + // Generators are used for generating documentation sites. + const generators = new Generators(); + const techdocsGenerator = new TechdocsGenerator(logger, config); + generators.register('techdocs', techdocsGenerator); + + // Publishers are used for + // 1. Publishing generated files to storage + // 2. Fetching files from storage and passing them to TechDocs frontend. const publisher = Publisher.fromConfig(config, logger, discovery); + // Docker client used by the generators. const dockerClient = new Docker(); return await createRouter({ diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index e649db0f22..c99f72e376 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-client +## 0.3.4 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + ## 0.3.3 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 36500c7c23..c878119a35 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@types/jest": "^26.0.7", "msw": "^0.21.2" }, diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 7316836a71..f6c2477d6c 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/catalog-model +## 0.6.0 + +### Minor Changes + +- ac3560b42: Remove `implementsApis` from `Component` entities. Deprecation happened in [#3449](https://github.com/backstage/backstage/pull/3449). + Use `providesApis` instead. + +### Patch Changes + +- c911061b7: Introduce a `profile` section for group entities that can optional include a + `displayName`, `email` and `picture`. +- 0e6298f7e: Ignore relations when comparing entities. This stops the refresh loop from rewriting entities over and over. + ## 0.5.0 ### Minor Changes diff --git a/packages/catalog-model/examples-relative/README.md b/packages/catalog-model/examples-relative/README.md deleted file mode 100644 index 3ed63a0e00..0000000000 --- a/packages/catalog-model/examples-relative/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Examples with relative paths - -These examples use Location entities with relative paths -[see #3513](https://github.com/backstage/backstage/pull/3513). - -The `examples` sibling directory will be replaced with these contents no sooner -than December 16 2020, to give consumers time to adopt the above change. - -The contents of this directory is here for consumers who are on the edge and -want to use the new facility before December 16. diff --git a/packages/catalog-model/examples-relative/acme-corp.yaml b/packages/catalog-model/examples-relative/acme-corp.yaml deleted file mode 100644 index 6449d548e0..0000000000 --- a/packages/catalog-model/examples-relative/acme-corp.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Location -metadata: - name: acme-corp - description: A collection of all Backstage example Groups -spec: - targets: - - ./acme/org.yaml diff --git a/packages/catalog-model/examples-relative/acme/backstage-group.yaml b/packages/catalog-model/examples-relative/acme/backstage-group.yaml deleted file mode 100644 index 1cfd469e99..0000000000 --- a/packages/catalog-model/examples-relative/acme/backstage-group.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: backstage - description: The backstage sub-department -spec: - type: sub-department - profile: - displayName: Backstage - email: backstage@example.com - picture: https://example.com/groups/backstage.jpeg - parent: infrastructure - ancestors: [infrastructure, acme-corp] - children: [team-a, team-b] - descendants: [team-a, team-b] diff --git a/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml b/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml deleted file mode 100644 index 4bb742bdb1..0000000000 --- a/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: boxoffice - description: The boxoffice sub-department -spec: - type: sub-department - profile: - displayName: Box Office - email: boxoffice@example.com - # Intentional no picture for testing - parent: infrastructure - ancestors: [infrastructure, acme-corp] - children: [team-c, team-d] - descendants: [team-c, team-d] diff --git a/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml b/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml deleted file mode 100644 index acfeef642c..0000000000 --- a/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: infrastructure - description: The infra department -spec: - type: department - # Intentional no profile for testing - parent: acme-corp - ancestors: [acme-corp] - children: [backstage, boxoffice] - descendants: [backstage, boxoffice, team-a, team-b, team-c, team-d] diff --git a/packages/catalog-model/examples-relative/acme/org.yaml b/packages/catalog-model/examples-relative/acme/org.yaml deleted file mode 100644 index 58cce827ff..0000000000 --- a/packages/catalog-model/examples-relative/acme/org.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: acme-corp - description: The acme-corp organization -spec: - type: organization - profile: - displayName: ACME Corp - email: info@example.com - picture: https://example.com/logo.jpeg - ancestors: [] - children: [infrastructure] - descendants: - [infrastructure, backstage, boxoffice, team-a, team-b, team-c, team-d] ---- -apiVersion: backstage.io/v1alpha1 -kind: Location -metadata: - name: example-groups - description: A collection of all Backstage example Groups -spec: - targets: - - ./infrastructure-group.yaml - - ./boxoffice-group.yaml - - ./backstage-group.yaml - - ./team-a-group.yaml - - ./team-b-group.yaml - - ./team-c-group.yaml - - ./team-d-group.yaml diff --git a/packages/catalog-model/examples-relative/acme/team-a-group.yaml b/packages/catalog-model/examples-relative/acme/team-a-group.yaml deleted file mode 100644 index 53d4bb8d80..0000000000 --- a/packages/catalog-model/examples-relative/acme/team-a-group.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: team-a - description: Team A -spec: - type: team - profile: - # Intentional no displayName for testing - email: team-a@example.com - picture: https://example.com/groups/team-a.jpeg - parent: backstage - ancestors: [backstage, infrastructure, acme-corp] - children: [] - descendants: [] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: breanna.davison -spec: - profile: - # Intentional no displayName for testing - email: breanna-davison@example.com - picture: https://example.com/staff/breanna.jpeg - memberOf: [team-a] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: janelle.dawe -spec: - profile: - displayName: Janelle Dawe - email: janelle-dawe@example.com - picture: https://example.com/staff/janelle.jpeg - memberOf: [team-a] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: nigel.manning -spec: - profile: - displayName: Nigel Manning - email: nigel-manning@example.com - picture: https://example.com/staff/nigel.jpeg - memberOf: [team-a] ---- -# This user is added as an example, to make it more easy for the "Guest" -# sign-in option to demonstrate some entities being owned. In a regular org, -# a guest user would probably not be registered like this. -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: guest -spec: - profile: - displayName: Guest User - email: guest@example.com - picture: https://example.com/staff/the-ceos-dog.jpeg - memberOf: [team-a] diff --git a/packages/catalog-model/examples-relative/acme/team-b-group.yaml b/packages/catalog-model/examples-relative/acme/team-b-group.yaml deleted file mode 100644 index a59a24317d..0000000000 --- a/packages/catalog-model/examples-relative/acme/team-b-group.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: team-b - description: Team B -spec: - type: team - profile: - displayName: Team B - email: team-b@example.com - picture: https://example.com/groups/team-b.jpeg - parent: backstage - ancestors: [backstage, infrastructure, acme-corp] - children: [] - descendants: [] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: amelia.park -spec: - profile: - displayName: Amelia Park - email: amelia-park@example.com - picture: https://example.com/staff/amelia.jpeg - memberOf: [team-b] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: colette.brock -spec: - profile: - displayName: Colette Brock - email: colette-brock@example.com - picture: https://example.com/staff/colette.jpeg - memberOf: [team-b] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: jenny.doe -spec: - profile: - displayName: Jenny Doe - email: jenny-doe@example.com - picture: https://example.com/staff/jenny.jpeg - memberOf: [team-b] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: jonathon.page -spec: - profile: - displayName: Jonathon Page - email: jonathon-page@example.com - picture: https://example.com/staff/jonathon.jpeg - memberOf: [team-b] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: justine.barrow -spec: - profile: - displayName: Justine Barrow - email: justine-barrow@example.com - picture: https://example.com/staff/justine.jpeg - memberOf: [team-b] diff --git a/packages/catalog-model/examples-relative/acme/team-c-group.yaml b/packages/catalog-model/examples-relative/acme/team-c-group.yaml deleted file mode 100644 index 31f67ac362..0000000000 --- a/packages/catalog-model/examples-relative/acme/team-c-group.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: team-c - description: Team C -spec: - type: team - profile: - displayName: Team C - email: team-c@example.com - picture: https://example.com/groups/team-c.jpeg - parent: boxoffice - ancestors: [boxoffice, infrastructure, acme-corp] - children: [] - descendants: [] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: calum.leavy -spec: - profile: - displayName: Calum Leavy - email: calum-leavy@example.com - picture: https://example.com/staff/calum.jpeg - memberOf: [team-c] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: frank.tiernan -spec: - profile: - displayName: Frank Tiernan - email: frank-tiernan@example.com - picture: https://example.com/staff/frank.jpeg - memberOf: [team-c] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: peadar.macmahon -spec: - profile: - displayName: Peadar MacMahon - email: peadar-macmahon@example.com - picture: https://example.com/staff/peadar.jpeg - memberOf: [team-c] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: sarah.gilroy -spec: - profile: - displayName: Sarah Gilroy - email: sarah-gilroy@example.com - picture: https://example.com/staff/sarah.jpeg - memberOf: [team-c] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: tara.macgovern -spec: - profile: - displayName: Tara MacGovern - email: tara-macgovern@example.com - picture: https://example.com/staff/tara.jpeg - memberOf: [team-c] diff --git a/packages/catalog-model/examples-relative/acme/team-d-group.yaml b/packages/catalog-model/examples-relative/acme/team-d-group.yaml deleted file mode 100644 index c4f87b3ac3..0000000000 --- a/packages/catalog-model/examples-relative/acme/team-d-group.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: team-d - description: Team D -spec: - type: team - profile: - displayName: Team D - email: team-d@example.com - picture: https://example.com/groups/team-d.jpeg - parent: boxoffice - ancestors: [boxoffice, infrastructure, acme-corp] - children: [] - descendants: [] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: eva.macdowell -spec: - profile: - displayName: Eva MacDowell - email: eva-macdowell@example.com - picture: https://example.com/staff/eva.jpeg - memberOf: [team-d] ---- -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: lucy.sheehan -spec: - profile: - displayName: Lucy Sheehan - email: lucy-sheehan@example.com - picture: https://example.com/staff/lucy.jpeg - memberOf: [team-d] diff --git a/packages/catalog-model/examples-relative/all-apis.yaml b/packages/catalog-model/examples-relative/all-apis.yaml deleted file mode 100644 index e23f1b3656..0000000000 --- a/packages/catalog-model/examples-relative/all-apis.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Location -metadata: - name: example-apis - description: A collection of all Backstage example APIs -spec: - targets: - - ./apis/hello-world-api.yaml - - ./apis/petstore-api.yaml - - ./apis/spotify-api.yaml - - ./apis/streetlights-api.yaml - - ./apis/swapi-graphql.yaml - - ./apis/wayback-archive-api.yaml - - ./apis/wayback-search-api.yaml diff --git a/packages/catalog-model/examples-relative/all-components.yaml b/packages/catalog-model/examples-relative/all-components.yaml deleted file mode 100644 index 5db5825b20..0000000000 --- a/packages/catalog-model/examples-relative/all-components.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Location -metadata: - name: example-components - description: A collection of all Backstage example components -spec: - targets: - - ./components/artist-lookup-component.yaml - - ./components/petstore-component.yaml - - ./components/playback-order-component.yaml - - ./components/podcast-api-component.yaml - - ./components/queue-proxy-component.yaml - - ./components/searcher-component.yaml - - ./components/playback-lib-component.yaml - - ./components/www-artist-component.yaml - - ./components/shuffle-api-component.yaml - - ./components/wayback-archive-component.yaml - - ./components/wayback-search-component.yaml diff --git a/packages/catalog-model/examples-relative/apis/hello-world-api.yaml b/packages/catalog-model/examples-relative/apis/hello-world-api.yaml deleted file mode 100644 index 0f9786329f..0000000000 --- a/packages/catalog-model/examples-relative/apis/hello-world-api.yaml +++ /dev/null @@ -1,48 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: hello-world - description: Hello World example for gRPC -spec: - type: grpc - lifecycle: deprecated - owner: team-c - definition: | - // Copyright 2015 gRPC 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. - - syntax = "proto3"; - - option java_multiple_files = true; - option java_package = "io.grpc.examples.helloworld"; - option java_outer_classname = "HelloWorldProto"; - option objc_class_prefix = "HLW"; - - package helloworld; - - // The greeting service definition. - service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} - } - - // The request message containing the user's name. - message HelloRequest { - string name = 1; - } - - // The response message containing the greetings - message HelloReply { - string message = 1; - } diff --git a/packages/catalog-model/examples-relative/apis/petstore-api.yaml b/packages/catalog-model/examples-relative/apis/petstore-api.yaml deleted file mode 100644 index a314b4e255..0000000000 --- a/packages/catalog-model/examples-relative/apis/petstore-api.yaml +++ /dev/null @@ -1,124 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: petstore - description: The petstore API - tags: - - store - - rest -spec: - type: openapi - lifecycle: experimental - owner: team-c - definition: | - openapi: "3.0.0" - info: - version: 1.0.0 - title: Swagger Petstore - license: - name: MIT - servers: - - url: http://petstore.swagger.io/v1 - paths: - /pets: - get: - summary: List all pets - operationId: listPets - tags: - - pets - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - format: int32 - responses: - '200': - description: A paged array of pets - headers: - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Pets" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - post: - summary: Create a pet - operationId: createPets - tags: - - pets - responses: - '201': - description: Null response - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - /pets/{petId}: - get: - summary: Info for a specific pet - operationId: showPetById - tags: - - pets - parameters: - - name: petId - in: path - required: true - description: The id of the pet to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Pet" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - components: - schemas: - Pet: - type: object - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - Pets: - type: array - items: - $ref: "#/components/schemas/Pet" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string diff --git a/packages/catalog-model/examples-relative/apis/spotify-api.yaml b/packages/catalog-model/examples-relative/apis/spotify-api.yaml deleted file mode 100644 index 0b8e80b86e..0000000000 --- a/packages/catalog-model/examples-relative/apis/spotify-api.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: spotify - description: The Spotify web API - tags: - - spotify - - rest - annotations: - # The annotation is deprecated, we use placeholders (see below) instead, remove it later. - backstage.io/definition-at-location: 'url:https://raw.githubusercontent.com/APIs-guru/openapi-directory/master/APIs/spotify.com/v1/swagger.yaml' -spec: - type: openapi - lifecycle: production - owner: team-a - definition: - $text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/spotify.com/v1/swagger.yaml diff --git a/packages/catalog-model/examples-relative/apis/streetlights-api.yaml b/packages/catalog-model/examples-relative/apis/streetlights-api.yaml deleted file mode 100644 index 725811d0cc..0000000000 --- a/packages/catalog-model/examples-relative/apis/streetlights-api.yaml +++ /dev/null @@ -1,221 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: streetlights - description: The Smartylighting Streetlights API allows you to remotely manage the city lights. - tags: - - mqtt -spec: - type: asyncapi - lifecycle: production - owner: team-c - definition: | - asyncapi: 2.0.0 - info: - title: Streetlights API - version: '1.0.0' - description: | - The Smartylighting Streetlights API allows you to remotely manage the city lights. - - ### Check out its awesome features: - - * Turn a specific streetlight on/off 🌃 - * Dim a specific streetlight 😎 - * Receive real-time information about environmental lighting conditions 📈 - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0 - - servers: - production: - url: api.streetlights.smartylighting.com:{port} - protocol: mqtt - description: Test broker - variables: - port: - description: Secure connection (TLS) is available through port 8883. - default: '1883' - enum: - - '1883' - - '8883' - security: - - apiKey: [] - - supportedOauthFlows: - - streetlights:on - - streetlights:off - - streetlights:dim - - openIdConnectWellKnown: [] - - defaultContentType: application/json - - channels: - smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: - description: The topic on which measured values may be produced and consumed. - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - subscribe: - summary: Receive information about environmental lighting conditions of a particular streetlight. - operationId: receiveLightMeasurement - traits: - - $ref: '#/components/operationTraits/kafka' - message: - $ref: '#/components/messages/lightMeasured' - - smartylighting/streetlights/1/0/action/{streetlightId}/turn/on: - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - publish: - operationId: turnOn - traits: - - $ref: '#/components/operationTraits/kafka' - message: - $ref: '#/components/messages/turnOnOff' - - smartylighting/streetlights/1/0/action/{streetlightId}/turn/off: - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - publish: - operationId: turnOff - traits: - - $ref: '#/components/operationTraits/kafka' - message: - $ref: '#/components/messages/turnOnOff' - - smartylighting/streetlights/1/0/action/{streetlightId}/dim: - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - publish: - operationId: dimLight - traits: - - $ref: '#/components/operationTraits/kafka' - message: - $ref: '#/components/messages/dimLight' - - components: - messages: - lightMeasured: - name: lightMeasured - title: Light measured - summary: Inform about environmental lighting conditions for a particular streetlight. - contentType: application/json - traits: - - $ref: '#/components/messageTraits/commonHeaders' - payload: - $ref: "#/components/schemas/lightMeasuredPayload" - turnOnOff: - name: turnOnOff - title: Turn on/off - summary: Command a particular streetlight to turn the lights on or off. - traits: - - $ref: '#/components/messageTraits/commonHeaders' - payload: - $ref: "#/components/schemas/turnOnOffPayload" - dimLight: - name: dimLight - title: Dim light - summary: Command a particular streetlight to dim the lights. - traits: - - $ref: '#/components/messageTraits/commonHeaders' - payload: - $ref: "#/components/schemas/dimLightPayload" - - schemas: - lightMeasuredPayload: - type: object - properties: - lumens: - type: integer - minimum: 0 - description: Light intensity measured in lumens. - sentAt: - $ref: "#/components/schemas/sentAt" - turnOnOffPayload: - type: object - properties: - command: - type: string - enum: - - on - - off - description: Whether to turn on or off the light. - sentAt: - $ref: "#/components/schemas/sentAt" - dimLightPayload: - type: object - properties: - percentage: - type: integer - description: Percentage to which the light should be dimmed to. - minimum: 0 - maximum: 100 - sentAt: - $ref: "#/components/schemas/sentAt" - sentAt: - type: string - format: date-time - description: Date and time when the message was sent. - - securitySchemes: - apiKey: - type: apiKey - in: user - description: Provide your API key as the user and leave the password empty. - supportedOauthFlows: - type: oauth2 - description: Flows to support OAuth 2.0 - flows: - implicit: - authorizationUrl: 'https://authserver.example/auth' - scopes: - 'streetlights:on': Ability to switch lights on - 'streetlights:off': Ability to switch lights off - 'streetlights:dim': Ability to dim the lights - password: - tokenUrl: 'https://authserver.example/token' - scopes: - 'streetlights:on': Ability to switch lights on - 'streetlights:off': Ability to switch lights off - 'streetlights:dim': Ability to dim the lights - clientCredentials: - tokenUrl: 'https://authserver.example/token' - scopes: - 'streetlights:on': Ability to switch lights on - 'streetlights:off': Ability to switch lights off - 'streetlights:dim': Ability to dim the lights - authorizationCode: - authorizationUrl: 'https://authserver.example/auth' - tokenUrl: 'https://authserver.example/token' - refreshUrl: 'https://authserver.example/refresh' - scopes: - 'streetlights:on': Ability to switch lights on - 'streetlights:off': Ability to switch lights off - 'streetlights:dim': Ability to dim the lights - openIdConnectWellKnown: - type: openIdConnect - openIdConnectUrl: 'https://authserver.example/.well-known' - - parameters: - streetlightId: - description: The ID of the streetlight. - schema: - type: string - - messageTraits: - commonHeaders: - headers: - type: object - properties: - my-app-header: - type: integer - minimum: 0 - maximum: 100 - - operationTraits: - kafka: - bindings: - kafka: - clientId: my-app-id diff --git a/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml b/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml deleted file mode 100644 index 0c1f7af5a4..0000000000 --- a/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml +++ /dev/null @@ -1,1176 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: starwars-graphql - description: SWAPI GraphQL Schema -spec: - type: graphql - lifecycle: production - owner: team-b - definition: | - schema { - query: Root - } - - """A single film.""" - type Film implements Node { - """The title of this film.""" - title: String - - """The episode number of this film.""" - episodeID: Int - - """The opening paragraphs at the beginning of this film.""" - openingCrawl: String - - """The name of the director of this film.""" - director: String - - """The name(s) of the producer(s) of this film.""" - producers: [String] - - """The ISO 8601 date format of film release at original creator country.""" - releaseDate: String - speciesConnection(after: String, first: Int, before: String, last: Int): FilmSpeciesConnection - starshipConnection(after: String, first: Int, before: String, last: Int): FilmStarshipsConnection - vehicleConnection(after: String, first: Int, before: String, last: Int): FilmVehiclesConnection - characterConnection(after: String, first: Int, before: String, last: Int): FilmCharactersConnection - planetConnection(after: String, first: Int, before: String, last: Int): FilmPlanetsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type FilmCharactersConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmCharactersEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - characters: [Person] - } - - """An edge in a connection.""" - type FilmCharactersEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type FilmPlanetsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmPlanetsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - planets: [Planet] - } - - """An edge in a connection.""" - type FilmPlanetsEdge { - """The item at the end of the edge""" - node: Planet - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type FilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type FilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type FilmSpeciesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmSpeciesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - species: [Species] - } - - """An edge in a connection.""" - type FilmSpeciesEdge { - """The item at the end of the edge""" - node: Species - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type FilmStarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmStarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] - } - - """An edge in a connection.""" - type FilmStarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type FilmVehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmVehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] - } - - """An edge in a connection.""" - type FilmVehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! - } - - """An object with an ID""" - interface Node { - """The id of the object.""" - id: ID! - } - - """Information about pagination in a connection.""" - type PageInfo { - """When paginating forwards, are there more items?""" - hasNextPage: Boolean! - - """When paginating backwards, are there more items?""" - hasPreviousPage: Boolean! - - """When paginating backwards, the cursor to continue.""" - startCursor: String - - """When paginating forwards, the cursor to continue.""" - endCursor: String - } - - """A connection to a list of items.""" - type PeopleConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PeopleEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - people: [Person] - } - - """An edge in a connection.""" - type PeopleEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """An individual person or character within the Star Wars universe.""" - type Person implements Node { - """The name of this person.""" - name: String - - """ - The birth year of the person, using the in-universe standard of BBY or ABY - - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is - a battle that occurs at the end of Star Wars episode IV: A New Hope. - """ - birthYear: String - - """ - The eye color of this person. Will be "unknown" if not known or "n/a" if the - person does not have an eye. - """ - eyeColor: String - - """ - The gender of this person. Either "Male", "Female" or "unknown", - "n/a" if the person does not have a gender. - """ - gender: String - - """ - The hair color of this person. Will be "unknown" if not known or "n/a" if the - person does not have hair. - """ - hairColor: String - - """The height of the person in centimeters.""" - height: Int - - """The mass of the person in kilograms.""" - mass: Float - - """The skin color of this person.""" - skinColor: String - - """A planet that this person was born on or inhabits.""" - homeworld: Planet - filmConnection(after: String, first: Int, before: String, last: Int): PersonFilmsConnection - - """The species that this person belongs to, or null if unknown.""" - species: Species - starshipConnection(after: String, first: Int, before: String, last: Int): PersonStarshipsConnection - vehicleConnection(after: String, first: Int, before: String, last: Int): PersonVehiclesConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type PersonFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type PersonFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type PersonStarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonStarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] - } - - """An edge in a connection.""" - type PersonStarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type PersonVehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonVehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] - } - - """An edge in a connection.""" - type PersonVehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! - } - - """ - A large mass, planet or planetoid in the Star Wars Universe, at the time of - 0 ABY. - """ - type Planet implements Node { - """The name of this planet.""" - name: String - - """The diameter of this planet in kilometers.""" - diameter: Int - - """ - The number of standard hours it takes for this planet to complete a single - rotation on its axis. - """ - rotationPeriod: Int - - """ - The number of standard days it takes for this planet to complete a single orbit - of its local star. - """ - orbitalPeriod: Int - - """ - A number denoting the gravity of this planet, where "1" is normal or 1 standard - G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. - """ - gravity: String - - """The average population of sentient beings inhabiting this planet.""" - population: Float - - """The climates of this planet.""" - climates: [String] - - """The terrains of this planet.""" - terrains: [String] - - """ - The percentage of the planet surface that is naturally occuring water or bodies - of water. - """ - surfaceWater: Float - residentConnection(after: String, first: Int, before: String, last: Int): PlanetResidentsConnection - filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type PlanetFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type PlanetFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type PlanetResidentsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetResidentsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - residents: [Person] - } - - """An edge in a connection.""" - type PlanetResidentsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type PlanetsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - planets: [Planet] - } - - """An edge in a connection.""" - type PlanetsEdge { - """The item at the end of the edge""" - node: Planet - - """A cursor for use in pagination""" - cursor: String! - } - - type Root { - allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection - film(id: ID, filmID: ID): Film - allPeople(after: String, first: Int, before: String, last: Int): PeopleConnection - person(id: ID, personID: ID): Person - allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection - planet(id: ID, planetID: ID): Planet - allSpecies(after: String, first: Int, before: String, last: Int): SpeciesConnection - species(id: ID, speciesID: ID): Species - allStarships(after: String, first: Int, before: String, last: Int): StarshipsConnection - starship(id: ID, starshipID: ID): Starship - allVehicles(after: String, first: Int, before: String, last: Int): VehiclesConnection - vehicle(id: ID, vehicleID: ID): Vehicle - - """Fetches an object given its ID""" - node( - """The ID of an object""" - id: ID! - ): Node - } - - """A type of person or character within the Star Wars Universe.""" - type Species implements Node { - """The name of this species.""" - name: String - - """The classification of this species, such as "mammal" or "reptile".""" - classification: String - - """The designation of this species, such as "sentient".""" - designation: String - - """The average height of this species in centimeters.""" - averageHeight: Float - - """The average lifespan of this species in years, null if unknown.""" - averageLifespan: Int - - """ - Common eye colors for this species, null if this species does not typically - have eyes. - """ - eyeColors: [String] - - """ - Common hair colors for this species, null if this species does not typically - have hair. - """ - hairColors: [String] - - """ - Common skin colors for this species, null if this species does not typically - have skin. - """ - skinColors: [String] - - """The language commonly spoken by this species.""" - language: String - - """A planet that this species originates from.""" - homeworld: Planet - personConnection(after: String, first: Int, before: String, last: Int): SpeciesPeopleConnection - filmConnection(after: String, first: Int, before: String, last: Int): SpeciesFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type SpeciesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - species: [Species] - } - - """An edge in a connection.""" - type SpeciesEdge { - """The item at the end of the edge""" - node: Species - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type SpeciesFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type SpeciesFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type SpeciesPeopleConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesPeopleEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - people: [Person] - } - - """An edge in a connection.""" - type SpeciesPeopleEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """A single transport craft that has hyperdrive capability.""" - type Starship implements Node { - """The name of this starship. The common name, such as "Death Star".""" - name: String - - """ - The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 - Orbital Battle Station". - """ - model: String - - """ - The class of this starship, such as "Starfighter" or "Deep Space Mobile - Battlestation" - """ - starshipClass: String - - """The manufacturers of this starship.""" - manufacturers: [String] - - """The cost of this starship new, in galactic credits.""" - costInCredits: Float - - """The length of this starship in meters.""" - length: Float - - """The number of personnel needed to run or pilot this starship.""" - crew: String - - """The number of non-essential people this starship can transport.""" - passengers: String - - """ - The maximum speed of this starship in atmosphere. null if this starship is - incapable of atmosphering flight. - """ - maxAtmospheringSpeed: Int - - """The class of this starships hyperdrive.""" - hyperdriveRating: Float - - """ - The Maximum number of Megalights this starship can travel in a standard hour. - A "Megalight" is a standard unit of distance and has never been defined before - within the Star Wars universe. This figure is only really useful for measuring - the difference in speed of starships. We can assume it is similar to AU, the - distance between our Sun (Sol) and Earth. - """ - MGLT: Int - - """The maximum number of kilograms that this starship can transport.""" - cargoCapacity: Float - - """ - The maximum length of time that this starship can provide consumables for its - entire crew without having to resupply. - """ - consumables: String - pilotConnection(after: String, first: Int, before: String, last: Int): StarshipPilotsConnection - filmConnection(after: String, first: Int, before: String, last: Int): StarshipFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type StarshipFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type StarshipFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type StarshipPilotsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipPilotsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - pilots: [Person] - } - - """An edge in a connection.""" - type StarshipPilotsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type StarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] - } - - """An edge in a connection.""" - type StarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! - } - - """A single transport craft that does not have hyperdrive capability""" - type Vehicle implements Node { - """ - The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder - bike". - """ - name: String - - """ - The model or official name of this vehicle. Such as "All-Terrain Attack - Transport". - """ - model: String - - """The class of this vehicle, such as "Wheeled" or "Repulsorcraft".""" - vehicleClass: String - - """The manufacturers of this vehicle.""" - manufacturers: [String] - - """The cost of this vehicle new, in Galactic Credits.""" - costInCredits: Float - - """The length of this vehicle in meters.""" - length: Float - - """The number of personnel needed to run or pilot this vehicle.""" - crew: String - - """The number of non-essential people this vehicle can transport.""" - passengers: String - - """The maximum speed of this vehicle in atmosphere.""" - maxAtmospheringSpeed: Int - - """The maximum number of kilograms that this vehicle can transport.""" - cargoCapacity: Float - - """ - The maximum length of time that this vehicle can provide consumables for its - entire crew without having to resupply. - """ - consumables: String - pilotConnection(after: String, first: Int, before: String, last: Int): VehiclePilotsConnection - filmConnection(after: String, first: Int, before: String, last: Int): VehicleFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! - } - - """A connection to a list of items.""" - type VehicleFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehicleFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] - } - - """An edge in a connection.""" - type VehicleFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type VehiclePilotsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehiclePilotsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - pilots: [Person] - } - - """An edge in a connection.""" - type VehiclePilotsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! - } - - """A connection to a list of items.""" - type VehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] - } - - """An edge in a connection.""" - type VehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! - } diff --git a/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml b/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml deleted file mode 100644 index 257344be3d..0000000000 --- a/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: artist-lookup - description: Artist Lookup - tags: - - java - - data -spec: - type: service - lifecycle: experimental - owner: team-a diff --git a/packages/catalog-model/examples-relative/components/petstore-component.yaml b/packages/catalog-model/examples-relative/components/petstore-component.yaml deleted file mode 100644 index e6dd56c274..0000000000 --- a/packages/catalog-model/examples-relative/components/petstore-component.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: petstore - description: Petstore -spec: - type: service - lifecycle: experimental - owner: team-c - implementsApis: - - petstore - - streetlights - - hello-world diff --git a/packages/catalog-model/examples-relative/components/playback-lib-component.yaml b/packages/catalog-model/examples-relative/components/playback-lib-component.yaml deleted file mode 100644 index f7d7670b5d..0000000000 --- a/packages/catalog-model/examples-relative/components/playback-lib-component.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: playback-sdk - description: Audio and video playback SDK -spec: - type: library - lifecycle: experimental - owner: team-c diff --git a/packages/catalog-model/examples-relative/components/playback-order-component.yaml b/packages/catalog-model/examples-relative/components/playback-order-component.yaml deleted file mode 100644 index c4f41b2b58..0000000000 --- a/packages/catalog-model/examples-relative/components/playback-order-component.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: playback-order - description: Playback Order - tags: - - java - - playback -spec: - type: service - lifecycle: production - owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/podcast-api-component.yaml b/packages/catalog-model/examples-relative/components/podcast-api-component.yaml deleted file mode 100644 index b89ff48c48..0000000000 --- a/packages/catalog-model/examples-relative/components/podcast-api-component.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: podcast-api - description: Podcast API - tags: - - java -spec: - type: service - lifecycle: experimental - owner: team-b diff --git a/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml b/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml deleted file mode 100644 index 7f7fcbd527..0000000000 --- a/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: queue-proxy - description: Queue Proxy - tags: - - go - - website -spec: - type: website - lifecycle: production - owner: team-b diff --git a/packages/catalog-model/examples-relative/components/searcher-component.yaml b/packages/catalog-model/examples-relative/components/searcher-component.yaml deleted file mode 100644 index 77150c96f0..0000000000 --- a/packages/catalog-model/examples-relative/components/searcher-component.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: searcher - description: Searcher - tags: - - go -spec: - type: service - lifecycle: production - owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml b/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml deleted file mode 100644 index 1c2da03511..0000000000 --- a/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: shuffle-api - description: Shuffle API - tags: - - go -spec: - type: service - lifecycle: production - owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/www-artist-component.yaml b/packages/catalog-model/examples-relative/components/www-artist-component.yaml deleted file mode 100644 index c333eb8c09..0000000000 --- a/packages/catalog-model/examples-relative/components/www-artist-component.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: www-artist - description: Artist main website -spec: - type: website - lifecycle: production - owner: team-a diff --git a/packages/catalog-model/examples/README.md b/packages/catalog-model/examples/README.md index abf4934f3f..77e1084899 100644 --- a/packages/catalog-model/examples/README.md +++ b/packages/catalog-model/examples/README.md @@ -1,7 +1,4 @@ # Example Entities -NOTE: These are being replaced with the contents of the `examples-relative` -sibling directory, after December 16 2020. If you are using this example data -you will need to be using a released version of the catalog backend which -supports relative targets in Location entities -[see #3513](https://github.com/backstage/backstage/pull/3513) after that time. +This is a set of example entities that you can make use of to demonstrate basic +Backstage features. diff --git a/packages/catalog-model/examples/acme-corp.yaml b/packages/catalog-model/examples/acme-corp.yaml index e8047fc143..6449d548e0 100644 --- a/packages/catalog-model/examples/acme-corp.yaml +++ b/packages/catalog-model/examples/acme-corp.yaml @@ -4,6 +4,5 @@ metadata: name: acme-corp description: A collection of all Backstage example Groups spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/org.yaml + - ./acme/org.yaml diff --git a/packages/catalog-model/examples/acme/backstage-group.yaml b/packages/catalog-model/examples/acme/backstage-group.yaml index be5baf091e..3aecfa0023 100644 --- a/packages/catalog-model/examples/acme/backstage-group.yaml +++ b/packages/catalog-model/examples/acme/backstage-group.yaml @@ -5,5 +5,9 @@ metadata: description: The backstage sub-department spec: type: sub-department + profile: + displayName: Backstage + email: backstage@example.com + picture: https://example.com/groups/backstage.jpeg parent: infrastructure children: [team-a, team-b] diff --git a/packages/catalog-model/examples/acme/boxoffice-group.yaml b/packages/catalog-model/examples/acme/boxoffice-group.yaml index 37e9816b50..fbd454c56e 100644 --- a/packages/catalog-model/examples/acme/boxoffice-group.yaml +++ b/packages/catalog-model/examples/acme/boxoffice-group.yaml @@ -5,5 +5,9 @@ metadata: description: The boxoffice sub-department spec: type: sub-department + profile: + displayName: Box Office + email: boxoffice@example.com + # Intentional no picture for testing parent: infrastructure children: [team-c, team-d] diff --git a/packages/catalog-model/examples/acme/infrastructure-group.yaml b/packages/catalog-model/examples/acme/infrastructure-group.yaml index 45bad12b7e..584578e6ce 100644 --- a/packages/catalog-model/examples/acme/infrastructure-group.yaml +++ b/packages/catalog-model/examples/acme/infrastructure-group.yaml @@ -5,5 +5,6 @@ metadata: description: The infra department spec: type: department + # Intentional no profile for testing parent: acme-corp children: [backstage, boxoffice] diff --git a/packages/catalog-model/examples/acme/org.yaml b/packages/catalog-model/examples/acme/org.yaml index 21a890a1aa..2b44183bc5 100644 --- a/packages/catalog-model/examples/acme/org.yaml +++ b/packages/catalog-model/examples/acme/org.yaml @@ -5,6 +5,10 @@ metadata: description: The acme-corp organization spec: type: organization + profile: + displayName: ACME Corp + email: info@example.com + picture: https://example.com/logo.jpeg children: [infrastructure] --- apiVersion: backstage.io/v1alpha1 @@ -13,12 +17,11 @@ metadata: name: example-groups description: A collection of all Backstage example Groups spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/infrastructure-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/boxoffice-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/backstage-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-a-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-b-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-c-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-d-group.yaml + - ./infrastructure-group.yaml + - ./boxoffice-group.yaml + - ./backstage-group.yaml + - ./team-a-group.yaml + - ./team-b-group.yaml + - ./team-c-group.yaml + - ./team-d-group.yaml diff --git a/packages/catalog-model/examples/acme/team-a-group.yaml b/packages/catalog-model/examples/acme/team-a-group.yaml index c3c2c590a1..ed736dce50 100644 --- a/packages/catalog-model/examples/acme/team-a-group.yaml +++ b/packages/catalog-model/examples/acme/team-a-group.yaml @@ -5,6 +5,10 @@ metadata: description: Team A spec: type: team + profile: + # Intentional no displayName for testing + email: team-a@example.com + picture: https://example.com/groups/team-a.jpeg parent: backstage children: [] --- @@ -14,7 +18,7 @@ metadata: name: breanna.davison spec: profile: - displayName: Breanna Davison + # Intentional no displayName for testing email: breanna-davison@example.com picture: https://example.com/staff/breanna.jpeg memberOf: [team-a] diff --git a/packages/catalog-model/examples/acme/team-b-group.yaml b/packages/catalog-model/examples/acme/team-b-group.yaml index 0c6604ff79..9ed50b04c2 100644 --- a/packages/catalog-model/examples/acme/team-b-group.yaml +++ b/packages/catalog-model/examples/acme/team-b-group.yaml @@ -5,6 +5,10 @@ metadata: description: Team B spec: type: team + profile: + displayName: Team B + email: team-b@example.com + picture: https://example.com/groups/team-b.jpeg parent: backstage children: [] --- diff --git a/packages/catalog-model/examples/acme/team-c-group.yaml b/packages/catalog-model/examples/acme/team-c-group.yaml index ccc95b7f60..7f151dbb1e 100644 --- a/packages/catalog-model/examples/acme/team-c-group.yaml +++ b/packages/catalog-model/examples/acme/team-c-group.yaml @@ -5,6 +5,10 @@ metadata: description: Team C spec: type: team + profile: + displayName: Team C + email: team-c@example.com + picture: https://example.com/groups/team-c.jpeg parent: boxoffice children: [] --- diff --git a/packages/catalog-model/examples/acme/team-d-group.yaml b/packages/catalog-model/examples/acme/team-d-group.yaml index e032ab8b9e..a0d3c2351a 100644 --- a/packages/catalog-model/examples/acme/team-d-group.yaml +++ b/packages/catalog-model/examples/acme/team-d-group.yaml @@ -5,6 +5,10 @@ metadata: description: Team D spec: type: team + profile: + displayName: Team D + email: team-d@example.com + picture: https://example.com/groups/team-d.jpeg parent: boxoffice children: [] --- diff --git a/packages/catalog-model/examples/all-apis.yaml b/packages/catalog-model/examples/all-apis.yaml index 0278fc3078..e23f1b3656 100644 --- a/packages/catalog-model/examples/all-apis.yaml +++ b/packages/catalog-model/examples/all-apis.yaml @@ -4,10 +4,11 @@ metadata: name: example-apis description: A collection of all Backstage example APIs spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/hello-world-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/petstore-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/spotify-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/streetlights-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/swapi-graphql.yaml + - ./apis/hello-world-api.yaml + - ./apis/petstore-api.yaml + - ./apis/spotify-api.yaml + - ./apis/streetlights-api.yaml + - ./apis/swapi-graphql.yaml + - ./apis/wayback-archive-api.yaml + - ./apis/wayback-search-api.yaml diff --git a/packages/catalog-model/examples/all-components.yaml b/packages/catalog-model/examples/all-components.yaml index 06c44b59d7..5db5825b20 100644 --- a/packages/catalog-model/examples/all-components.yaml +++ b/packages/catalog-model/examples/all-components.yaml @@ -4,14 +4,15 @@ metadata: name: example-components description: A collection of all Backstage example components spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/artist-lookup-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/petstore-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-order-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/podcast-api-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/queue-proxy-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/searcher-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-lib-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/www-artist-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/shuffle-api-component.yaml + - ./components/artist-lookup-component.yaml + - ./components/petstore-component.yaml + - ./components/playback-order-component.yaml + - ./components/podcast-api-component.yaml + - ./components/queue-proxy-component.yaml + - ./components/searcher-component.yaml + - ./components/playback-lib-component.yaml + - ./components/www-artist-component.yaml + - ./components/shuffle-api-component.yaml + - ./components/wayback-archive-component.yaml + - ./components/wayback-search-component.yaml diff --git a/packages/catalog-model/examples-relative/apis/wayback-archive-api.yaml b/packages/catalog-model/examples/apis/wayback-archive-api.yaml similarity index 91% rename from packages/catalog-model/examples-relative/apis/wayback-archive-api.yaml rename to packages/catalog-model/examples/apis/wayback-archive-api.yaml index 82610eae24..dbed93dbe8 100644 --- a/packages/catalog-model/examples-relative/apis/wayback-archive-api.yaml +++ b/packages/catalog-model/examples/apis/wayback-archive-api.yaml @@ -6,6 +6,6 @@ metadata: spec: type: openapi lifecycle: production - owner: archive@example.com + owner: team-a definition: $text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/archive.org/wayback/1.0.0/openapi.yaml diff --git a/packages/catalog-model/examples-relative/apis/wayback-search-api.yaml b/packages/catalog-model/examples/apis/wayback-search-api.yaml similarity index 91% rename from packages/catalog-model/examples-relative/apis/wayback-search-api.yaml rename to packages/catalog-model/examples/apis/wayback-search-api.yaml index 6eb5cae54b..b39b5df468 100644 --- a/packages/catalog-model/examples-relative/apis/wayback-search-api.yaml +++ b/packages/catalog-model/examples/apis/wayback-search-api.yaml @@ -6,6 +6,6 @@ metadata: spec: type: openapi lifecycle: production - owner: archive@example.com + owner: team-a definition: $text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/archive.org/search/1.0.0/openapi.yaml diff --git a/packages/catalog-model/examples/components/petstore-component.yaml b/packages/catalog-model/examples/components/petstore-component.yaml index e6dd56c274..acbb2f82b0 100644 --- a/packages/catalog-model/examples/components/petstore-component.yaml +++ b/packages/catalog-model/examples/components/petstore-component.yaml @@ -7,7 +7,7 @@ spec: type: service lifecycle: experimental owner: team-c - implementsApis: + providesApis: - petstore - streetlights - hello-world diff --git a/packages/catalog-model/examples-relative/components/wayback-archive-component.yaml b/packages/catalog-model/examples/components/wayback-archive-component.yaml similarity index 88% rename from packages/catalog-model/examples-relative/components/wayback-archive-component.yaml rename to packages/catalog-model/examples/components/wayback-archive-component.yaml index ea5ef10a17..5d558db64a 100644 --- a/packages/catalog-model/examples-relative/components/wayback-archive-component.yaml +++ b/packages/catalog-model/examples/components/wayback-archive-component.yaml @@ -6,6 +6,6 @@ metadata: spec: type: service lifecycle: production - owner: archive@example.com + owner: team-a providesApis: - wayback-archive diff --git a/packages/catalog-model/examples-relative/components/wayback-search-component.yaml b/packages/catalog-model/examples/components/wayback-search-component.yaml similarity index 89% rename from packages/catalog-model/examples-relative/components/wayback-search-component.yaml rename to packages/catalog-model/examples/components/wayback-search-component.yaml index def136ff2f..0187e4441f 100644 --- a/packages/catalog-model/examples-relative/components/wayback-search-component.yaml +++ b/packages/catalog-model/examples/components/wayback-search-component.yaml @@ -6,7 +6,7 @@ metadata: spec: type: service lifecycle: production - owner: archive@example.com + owner: team-a providesApis: - wayback-search consumesApis: diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index ad0a2740f7..4fad95e122 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "0.5.0", + "version": "0.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@types/express": "^4.17.6", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", diff --git a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.test.ts b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.test.ts index 8eec63daac..030c99c151 100644 --- a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.test.ts +++ b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.test.ts @@ -33,7 +33,6 @@ describe('ComponentV1alpha1Validator', () => { type: 'service', lifecycle: 'production', owner: 'me', - implementsApis: ['api-0'], providesApis: ['api-0'], consumesApis: ['api-0'], }, @@ -104,26 +103,6 @@ describe('ComponentV1alpha1Validator', () => { await expect(validator.check(entity)).rejects.toThrow(/owner/); }); - it('accepts missing implementsApis', async () => { - delete (entity as any).spec.implementsApis; - await expect(validator.check(entity)).resolves.toBe(true); - }); - - it('rejects empty implementsApis', async () => { - (entity as any).spec.implementsApis = ['']; - await expect(validator.check(entity)).rejects.toThrow(/implementsApis/); - }); - - it('rejects undefined implementsApis', async () => { - (entity as any).spec.implementsApis = [undefined]; - await expect(validator.check(entity)).rejects.toThrow(/implementsApis/); - }); - - it('accepts no implementsApis', async () => { - (entity as any).spec.implementsApis = []; - await expect(validator.check(entity)).resolves.toBe(true); - }); - it('accepts missing providesApis', async () => { delete (entity as any).spec.providesApis; await expect(validator.check(entity)).resolves.toBe(true); diff --git a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts index 680674f16e..e511dcb24a 100644 --- a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts @@ -29,7 +29,6 @@ const schema = yup.object>({ type: yup.string().required().min(1), lifecycle: yup.string().required().min(1), owner: yup.string().required().min(1), - implementsApis: yup.array(yup.string().required()).notRequired(), providesApis: yup.array(yup.string().required()).notRequired(), consumesApis: yup.array(yup.string().required()).notRequired(), }) @@ -43,12 +42,6 @@ export interface ComponentEntityV1alpha1 extends Entity { type: string; lifecycle: string; owner: string; - /** - * @deprecated This field will disappear on Dec 14th, 2020. Please remove - * any consuming code. The new field providesApis provides the - * same functionality like before. - */ - implementsApis?: string[]; providesApis?: string[]; consumesApis?: string[]; }; diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index ddf7a7ee76..8f73247301 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli +## 0.4.2 + +### Patch Changes + +- c36a01b4c: Re-enable symlink resolution during bundling, and switch to using a resolve plugin for external linked packages. + ## 0.4.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 142caa083f..d8e1a96b46 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.4.1", + "version": "0.4.2", "private": false, "publishConfig": { "access": "public" @@ -111,9 +111,9 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.4.0", + "@backstage/backend-common": "^0.4.1", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts index cd0a6f3221..c690e0bbc9 100644 --- a/packages/config/src/reader.ts +++ b/packages/config/src/reader.ts @@ -69,7 +69,7 @@ export class ConfigReader implements Config { constructor( private readonly data: JsonObject | undefined, - private readonly context: string = 'empty-config', + private readonly context: string = 'mock-config', private readonly fallback?: ConfigReader, private readonly prefix: string = '', ) {} diff --git a/packages/core-api/CHANGELOG.md b/packages/core-api/CHANGELOG.md index 79aa22f481..de997bf065 100644 --- a/packages/core-api/CHANGELOG.md +++ b/packages/core-api/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-api +## 0.2.6 + +### Patch Changes + +- 7dd2ef7d1: Use auth provider ID to create unique session storage keys for GitHub and SAML Auth. + ## 0.2.5 ### Patch Changes diff --git a/packages/core-api/package.json b/packages/core-api/package.json index 05acadffd5..fa8bd7a086 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-api", "description": "Internal Core API used by Backstage plugins and apps", - "version": "0.2.5", + "version": "0.2.6", "private": false, "publishConfig": { "access": "public", @@ -43,7 +43,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/test-utils-core": "^0.1.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts index 812032a8a3..a7c945a907 100644 --- a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts @@ -84,7 +84,7 @@ class GithubAuth implements OAuthApi, SessionApi { const authSessionStore = new AuthSessionStore({ manager: sessionManager, - storageKey: 'githubSession', + storageKey: `${provider.id}Session`, sessionScopes: (session: GithubSession) => session.providerInfo.scopes, }); diff --git a/packages/core-api/src/apis/implementations/auth/saml/SamlAuth.ts b/packages/core-api/src/apis/implementations/auth/saml/SamlAuth.ts index da5f082c9b..e05f6266d6 100644 --- a/packages/core-api/src/apis/implementations/auth/saml/SamlAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/saml/SamlAuth.ts @@ -63,7 +63,7 @@ class SamlAuth implements ProfileInfoApi, BackstageIdentityApi, SessionApi { const authSessionStore = new AuthSessionStore({ manager: sessionManager, - storageKey: 'samlSession', + storageKey: `${provider.id}Session`, }); return new SamlAuth(authSessionStore); diff --git a/packages/core-api/src/app/App.test.tsx b/packages/core-api/src/app/App.test.tsx new file mode 100644 index 0000000000..8dd40d52b0 --- /dev/null +++ b/packages/core-api/src/app/App.test.tsx @@ -0,0 +1,185 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { renderWithEffects, withLogCollector } from '@backstage/test-utils'; +import { lightTheme } from '@backstage/theme'; +import { render, screen } from '@testing-library/react'; +import React, { PropsWithChildren } from 'react'; +import { BrowserRouter, Routes } from 'react-router-dom'; +import { createRoutableExtension } from '../extensions'; +import { defaultSystemIcons } from '../icons'; +import { createPlugin } from '../plugin'; +import { useRouteRef } from '../routing/hooks'; +import { createExternalRouteRef, createRouteRef } from '../routing/RouteRef'; +import { generateBoundRoutes, PrivateAppImpl } from './App'; + +describe('generateBoundRoutes', () => { + it('runs happy path', () => { + const external = { myRoute: createExternalRouteRef() }; + const ref = createRouteRef({ path: '', title: '' }); + const result = generateBoundRoutes(({ bind }) => { + bind(external, { myRoute: ref }); + }); + + expect(result.get(external.myRoute)).toBe(ref); + }); + + it('throws on unknown keys', () => { + const external = { myRoute: createExternalRouteRef() }; + const ref = createRouteRef({ path: '', title: '' }); + expect(() => + generateBoundRoutes(({ bind }) => { + bind(external, { someOtherRoute: ref } as any); + }), + ).toThrow('Key someOtherRoute is not an existing external route'); + }); +}); + +describe('Integration Test', () => { + const plugin1RouteRef = createRouteRef({ path: '/blah1', title: '' }); + const plugin2RouteRef = createRouteRef({ path: '/blah2', title: '' }); + const externalRouteRef = createExternalRouteRef(); + + const plugin1 = createPlugin({ + id: 'blob', + externalRoutes: { + foo: externalRouteRef, + }, + }); + + const plugin2 = createPlugin({ + id: 'plugin2', + }); + + const HiddenComponent = plugin2.provide( + createRoutableExtension({ + component: () => Promise.resolve((_: { path?: string }) =>
), + mountPoint: plugin2RouteRef, + }), + ); + + const ExposedComponent = plugin1.provide( + createRoutableExtension({ + component: () => + Promise.resolve((_: PropsWithChildren<{ path?: string }>) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const routeRefFunction = useRouteRef(externalRouteRef); + return
Our Route Is: {routeRefFunction({})}
; + }), + mountPoint: plugin1RouteRef, + }), + ); + + it('runs happy path', async () => { + const components = { + NotFoundErrorPage: () => null, + BootErrorPage: () => null, + Progress: () => null, + Router: BrowserRouter, + }; + + const app = new PrivateAppImpl({ + apis: [], + defaultApis: [], + themes: [ + { + id: 'light', + title: 'Light Theme', + variant: 'light', + theme: lightTheme, + }, + ], + icons: defaultSystemIcons, + plugins: [], + components, + bindRoutes: ({ bind }) => { + bind(plugin1.externalRoutes, { foo: plugin2RouteRef }); + }, + }); + + const Provider = app.getProvider(); + const Router = app.getRouter(); + + await renderWithEffects( + + + + + + + + , + ); + + expect(screen.getByText('Our Route Is: /foo/bar')).toBeInTheDocument(); + }); + + it('should throw some error when the route has duplicate params', () => { + const components = { + NotFoundErrorPage: () => null, + BootErrorPage: () => null, + Progress: () => null, + Router: BrowserRouter, + }; + + const app = new PrivateAppImpl({ + apis: [], + defaultApis: [], + themes: [ + { + id: 'light', + title: 'Light Theme', + variant: 'light', + theme: lightTheme, + }, + ], + icons: defaultSystemIcons, + plugins: [], + components, + bindRoutes: ({ bind }) => { + bind(plugin1.externalRoutes, { foo: plugin2RouteRef }); + }, + }); + + const Provider = app.getProvider(); + const Router = app.getRouter(); + const { error: errorLogs } = withLogCollector(() => { + expect(() => + render( + + + + + + + + + , + ), + ).toThrow( + 'Parameter :thing is duplicated in path /test/:thing/some/:thing', + ); + }); + expect(errorLogs).toEqual([ + expect.stringContaining( + 'Parameter :thing is duplicated in path /test/:thing/some/:thing', + ), + expect.stringContaining( + 'The above error occurred in the component', + ), + ]); + }); +}); diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx index 3ca91966bf..2aaeba9796 100644 --- a/packages/core-api/src/app/App.tsx +++ b/packages/core-api/src/app/App.tsx @@ -13,57 +13,95 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React, { ComponentType, + PropsWithChildren, + ReactElement, useMemo, useState, - ReactElement, - PropsWithChildren, } from 'react'; -import { Route, Routes, Navigate } from 'react-router-dom'; -import { AppContextProvider } from './AppContext'; -import { - BackstageApp, - AppComponents, - AppConfigLoader, - SignInResult, - SignInPageProps, -} from './types'; -import { BackstagePlugin } from '../plugin'; -import { - featureFlagsApiRef, - AppThemeApi, - ConfigApi, - identityApiRef, -} from '../apis/definitions'; -import { AppThemeProvider } from './AppThemeProvider'; - -import { IconComponent, SystemIcons, SystemIconKey } from '../icons'; +import { Navigate, Route, Routes } from 'react-router-dom'; +import { useAsync } from 'react-use'; import { + AnyApiFactory, + ApiHolder, ApiProvider, ApiRegistry, AppTheme, - AppThemeSelector, appThemeApiRef, + AppThemeSelector, configApiRef, ConfigReader, - useApi, - AnyApiFactory, - ApiHolder, LocalStorageFeatureFlags, + useApi, } from '../apis'; -import { useAsync } from 'react-use'; +import { + AppThemeApi, + ConfigApi, + featureFlagsApiRef, + identityApiRef, +} from '../apis/definitions'; +import { ApiFactoryRegistry, ApiResolver } from '../apis/system'; +import { + childDiscoverer, + routeElementDiscoverer, + traverseElementTree, +} from '../extensions/traversal'; +import { IconComponent, SystemIconKey, SystemIcons } from '../icons'; +import { BackstagePlugin } from '../plugin'; +import { RouteRef } from '../routing'; +import { + routeObjectCollector, + routeParentCollector, + routePathCollector, +} from '../routing/collectors'; +import { RoutingProvider, validateRoutes } from '../routing/hooks'; +import { ExternalRouteRef } from '../routing/RouteRef'; +import { AppContextProvider } from './AppContext'; import { AppIdentity } from './AppIdentity'; -import { ApiResolver, ApiFactoryRegistry } from '../apis/system'; +import { AppThemeProvider } from './AppThemeProvider'; +import { + AppComponents, + AppConfigLoader, + AppOptions, + AppRouteBinder, + BackstageApp, + SignInPageProps, + SignInResult, +} from './types'; + +export function generateBoundRoutes( + bindRoutes: AppOptions['bindRoutes'], +): Map { + const result = new Map(); + + if (bindRoutes) { + const bind: AppRouteBinder = (externalRoutes, targetRoutes) => { + for (const [key, value] of Object.entries(targetRoutes)) { + const externalRoute = externalRoutes[key]; + if (!externalRoute) { + throw new Error(`Key ${key} is not an existing external route`); + } + + result.set(externalRoute, value); + } + }; + bindRoutes({ bind }); + } + + return result; +} type FullAppOptions = { apis: Iterable; icons: SystemIcons; - plugins: BackstagePlugin[]; + plugins: BackstagePlugin[]; components: AppComponents; themes: AppTheme[]; configLoader?: AppConfigLoader; defaultApis: Iterable; + bindRoutes?: AppOptions['bindRoutes']; }; function useConfigLoader( @@ -107,11 +145,12 @@ export class PrivateAppImpl implements BackstageApp { private readonly apis: Iterable; private readonly icons: SystemIcons; - private readonly plugins: BackstagePlugin[]; + private readonly plugins: BackstagePlugin[]; private readonly components: AppComponents; private readonly themes: AppTheme[]; private readonly configLoader?: AppConfigLoader; private readonly defaultApis: Iterable; + private readonly bindRoutes: AppOptions['bindRoutes']; private readonly identityApi = new AppIdentity(); @@ -123,9 +162,10 @@ export class PrivateAppImpl implements BackstageApp { this.themes = options.themes; this.configLoader = options.configLoader; this.defaultApis = options.defaultApis; + this.bindRoutes = options.bindRoutes; } - getPlugins(): BackstagePlugin[] { + getPlugins(): BackstagePlugin[] { return this.plugins; } @@ -202,6 +242,22 @@ export class PrivateAppImpl implements BackstageApp { [], ); + const { routePaths, routeParents, routeObjects } = useMemo(() => { + const result = traverseElementTree({ + root: children, + discoverers: [childDiscoverer, routeElementDiscoverer], + collectors: { + routePaths: routePathCollector, + routeParents: routeParentCollector, + routeObjects: routeObjectCollector, + }, + }); + + validateRoutes(result.routePaths, result.routeParents); + + return result; + }, [children]); + const loadedConfig = useConfigLoader( this.configLoader, this.components, @@ -218,7 +274,16 @@ export class PrivateAppImpl implements BackstageApp { return ( - {children} + + + {children} + + ); diff --git a/packages/core-api/src/app/types.ts b/packages/core-api/src/app/types.ts index 8a1eb92e8e..b6b1002d12 100644 --- a/packages/core-api/src/app/types.ts +++ b/packages/core-api/src/app/types.ts @@ -16,7 +16,8 @@ import { ComponentType } from 'react'; import { IconComponent, SystemIconKey, SystemIcons } from '../icons'; -import { BackstagePlugin } from '../plugin'; +import { BackstagePlugin, AnyExternalRoutes } from '../plugin/types'; +import { RouteRef } from '../routing'; import { AnyApiFactory } from '../apis'; import { AppTheme, ProfileInfo } from '../apis/definitions'; import { AppConfig } from '@backstage/config'; @@ -78,6 +79,11 @@ export type AppComponents = { */ export type AppConfigLoader = () => Promise; +export type AppRouteBinder = ( + externalRoutes: T, + targetRoutes: { [key in keyof T]: RouteRef }, +) => void; + export type AppOptions = { /** * A collection of ApiFactories to register in the application to either @@ -93,7 +99,7 @@ export type AppOptions = { /** * A list of all plugins to include in the app. */ - plugins?: BackstagePlugin[]; + plugins?: BackstagePlugin[]; /** * Supply components to the app to override the default ones. @@ -134,13 +140,33 @@ export type AppOptions = { * that was packaged by the backstage-cli and default docker container boot script. */ configLoader?: AppConfigLoader; + + /** + * A function that is used to register associations between cross-plugin route + * references, enabling plugins to navigate between each other. + * + * The `bind` function that is passed in should be used to bind all external + * routes of all used plugins. + * + * ```ts + * bindRoutes({ bind }) { + * bind(docsPlugin.externalRoutes, { + * homePage: managePlugin.routes.managePage, + * }) + * bind(homePagePlugin.externalRoutes, { + * settingsPage: settingsPlugin.routes.settingsPage, + * }) + * } + * ``` + */ + bindRoutes?(context: { bind: AppRouteBinder }): void; }; export type BackstageApp = { /** * Returns all plugins registered for the app. */ - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; /** * Get a common icon for this app. diff --git a/packages/core-api/src/extensions/extensions.test.tsx b/packages/core-api/src/extensions/extensions.test.tsx index 92fcecebc4..26755b3bcf 100644 --- a/packages/core-api/src/extensions/extensions.test.tsx +++ b/packages/core-api/src/extensions/extensions.test.tsx @@ -30,10 +30,12 @@ const plugin = createPlugin({ describe('extensions', () => { it('should create a react extension with component data', () => { - const Component = () => null; + const Component = () =>
; const extension = createReactExtension({ - component: Component, + component: { + sync: Component, + }, data: { myData: { foo: 'bar' }, }, @@ -47,15 +49,17 @@ describe('extensions', () => { }); it('should create react extensions of different types', () => { - const Component = () => null; + const Component = () =>
; const routeRef = createRouteRef({ path: '/foo', title: 'Foo' }); const extension1 = createComponentExtension({ - component: Component, + component: { + sync: Component, + }, }); const extension2 = createRoutableExtension({ - component: Component, + component: () => Promise.resolve(Component), mountPoint: routeRef, }); diff --git a/packages/core-api/src/extensions/extensions.tsx b/packages/core-api/src/extensions/extensions.tsx index 4087d5f963..e56b6901dd 100644 --- a/packages/core-api/src/extensions/extensions.tsx +++ b/packages/core-api/src/extensions/extensions.tsx @@ -14,59 +14,96 @@ * limitations under the License. */ -import React, { - NamedExoticComponent, - ComponentType, - PropsWithChildren, -} from 'react'; -import { RouteRef } from '../routing'; +import React, { lazy, Suspense } from 'react'; +import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; import { Extension, BackstagePlugin } from '../plugin/types'; -export function createRoutableExtension(options: { - component: ComponentType; +type ComponentLoader = + | { + lazy: () => Promise; + } + | { + sync: T; + }; + +export function createRoutableExtension< + T extends (props: any) => JSX.Element +>(options: { + component: () => Promise; mountPoint: RouteRef; - // TODO(Rugvip): We want to carry forward the exact props type from the inner component, with - // or without children. ComponentType stops us from doing that though, as it always - // adds children to the props internally. We may want to work around this with custom types. -}): Extension< - NamedExoticComponent> -> { +}): Extension { const { component, mountPoint } = options; return createReactExtension({ - component, + component: { + lazy: () => + component().then(InnerComponent => { + const RoutableExtensionWrapper = ((props: any) => { + // Validate that the routing is wired up correctly in the App.tsx + try { + useRouteRef(mountPoint); + } catch { + throw new Error( + 'Routable extension component was not discovered in the app element tree. ' + + 'Routable extension components may not be rendered by other components and must be ' + + 'directly available as an element within the App provider component.', + ); + } + return ; + }) as T; + return RoutableExtensionWrapper; + }), + }, data: { 'core.mountPoint': mountPoint, }, }); } -export function createComponentExtension(options: { - component: ComponentType; -}): Extension> { +export function createComponentExtension< + T extends (props: any) => JSX.Element +>(options: { component: ComponentLoader }): Extension { const { component } = options; return createReactExtension({ component }); } -export function createReactExtension(options: { - component: ComponentType; +export function createReactExtension< + T extends (props: any) => JSX.Element +>(options: { + component: ComponentLoader; data?: Record; -}): Extension> { - const { component: Component, data = {} } = options; +}): Extension { + const { data = {} } = options; + + let Component: T; + if ('lazy' in options.component) { + const lazyLoader = options.component.lazy; + Component = (lazy(() => + lazyLoader().then(component => ({ default: component })), + ) as unknown) as T; + } else { + Component = options.component.sync; + } + const componentName = + (Component as { displayName?: string }).displayName || + Component.name || + 'Component'; + return { - expose(plugin: BackstagePlugin): NamedExoticComponent { - const Result = (props: Props) => ; + expose(plugin: BackstagePlugin) { + const Result: any = (props: any) => ( + + + + ); attachComponentData(Result, 'core.plugin', plugin); for (const [key, value] of Object.entries(data)) { attachComponentData(Result, key, value); } - const name = Component.displayName || Component.name || 'Component'; - if (name) { - Result.displayName = `Extension(${name})`; - } - return Result as NamedExoticComponent; + Result.displayName = `Extension(${componentName})`; + return Result; }, }; } diff --git a/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.test.ts b/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.test.ts index 4572b923dd..5c960f7876 100644 --- a/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.test.ts +++ b/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.test.ts @@ -36,6 +36,7 @@ class LocalStorage { } class MockManager implements SessionManager { + setSession = jest.fn(); getSession = jest.fn(); removeSession = jest.fn(); sessionState$ = jest.fn(); @@ -59,6 +60,7 @@ describe('GheAuth AuthSessionStore', () => { await expect(store.getSession({})).resolves.toBe('a b c'); expect(manager.getSession).not.toHaveBeenCalled(); + expect(manager.setSession).toHaveBeenCalledWith('a b c'); }); it('should not use session without enough scope', async () => { @@ -72,6 +74,7 @@ describe('GheAuth AuthSessionStore', () => { 'a b c d', ); expect(manager.getSession).toHaveBeenCalledTimes(1); + expect(manager.setSession).not.toHaveBeenCalled(); }); it('should not use expired session', async () => { @@ -87,6 +90,7 @@ describe('GheAuth AuthSessionStore', () => { await expect(store.getSession({})).resolves.toBe('123'); expect(manager.getSession).toHaveBeenCalledTimes(1); + expect(manager.setSession).not.toHaveBeenCalled(); }); it('should not load missing session', async () => { @@ -96,6 +100,7 @@ describe('GheAuth AuthSessionStore', () => { await expect(store.getSession({})).resolves.toBe('123'); expect(manager.getSession).toHaveBeenCalledTimes(1); + expect(manager.setSession).not.toHaveBeenCalled(); expect(localStorage.getItem('my-key')).toBe('"123"'); }); @@ -109,6 +114,7 @@ describe('GheAuth AuthSessionStore', () => { await expect(store.getSession({})).resolves.toBe('123'); expect(manager.getSession).toHaveBeenCalledTimes(1); + expect(manager.setSession).not.toHaveBeenCalled(); }); it('should clear session', () => { @@ -119,6 +125,7 @@ describe('GheAuth AuthSessionStore', () => { store.removeSession(); expect(localStorage.getItem('my-key')).toBe(null); + expect(manager.removeSession).toHaveBeenCalled(); }); it('should forward sessionState calls', () => { diff --git a/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.ts b/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.ts index e82557b1ce..224036d283 100644 --- a/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.ts +++ b/packages/core-api/src/lib/AuthSessionManager/AuthSessionStore.ts @@ -16,6 +16,7 @@ import { SessionManager, + MutableSessionManager, SessionScopesFunc, SessionShouldRefreshFunc, GetSessionOptions, @@ -24,7 +25,7 @@ import { SessionScopeHelper } from './common'; type Options = { /** The connector used for acting on the auth session */ - manager: SessionManager; + manager: MutableSessionManager; /** Storage key to use to store sessions */ storageKey: string; /** Used to get the scope of the session */ @@ -40,7 +41,7 @@ type Options = { * Session is serialized to JSON with special support for following types: Set. */ export class AuthSessionStore implements SessionManager { - private readonly manager: SessionManager; + private readonly manager: MutableSessionManager; private readonly storageKey: string; private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc; private readonly helper: SessionScopeHelper; @@ -70,6 +71,7 @@ export class AuthSessionStore implements SessionManager { const shouldRefresh = this.sessionShouldRefreshFunc(session!); if (!shouldRefresh) { + this.manager.setSession(session!); return session!; } } diff --git a/packages/core-api/src/lib/AuthSessionManager/StaticAuthSessionManager.ts b/packages/core-api/src/lib/AuthSessionManager/StaticAuthSessionManager.ts index e02b600828..e4f144b0a9 100644 --- a/packages/core-api/src/lib/AuthSessionManager/StaticAuthSessionManager.ts +++ b/packages/core-api/src/lib/AuthSessionManager/StaticAuthSessionManager.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SessionManager, GetSessionOptions } from './types'; +import { MutableSessionManager, GetSessionOptions } from './types'; import { AuthConnector } from '../AuthConnector'; import { SessionScopeHelper } from './common'; import { SessionStateTracker } from './SessionStateTracker'; @@ -31,7 +31,7 @@ type Options = { /** * StaticAuthSessionManager manages an underlying session that does not expire. */ -export class StaticAuthSessionManager implements SessionManager { +export class StaticAuthSessionManager implements MutableSessionManager { private readonly connector: AuthConnector; private readonly helper: SessionScopeHelper; private readonly stateTracker = new SessionStateTracker(); @@ -45,6 +45,11 @@ export class StaticAuthSessionManager implements SessionManager { this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes }); } + setSession(session: T | undefined): void { + this.currentSession = session; + this.stateTracker.setIsSignedIn(Boolean(session)); + } + async getSession(options: GetSessionOptions): Promise { if ( this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes) diff --git a/packages/core-api/src/lib/AuthSessionManager/types.ts b/packages/core-api/src/lib/AuthSessionManager/types.ts index 804c7121e1..f57afd6760 100644 --- a/packages/core-api/src/lib/AuthSessionManager/types.ts +++ b/packages/core-api/src/lib/AuthSessionManager/types.ts @@ -36,6 +36,13 @@ export type SessionManager = { sessionState$(): Observable; }; +/** + * An extension of the session manager where the session can also be pushed from the manager. + */ +export interface MutableSessionManager extends SessionManager { + setSession(session: T | undefined): void; +} + /** * A function called to determine the scopes of a session. */ diff --git a/packages/core-api/src/plugin/Plugin.tsx b/packages/core-api/src/plugin/Plugin.tsx index f477674f4d..dd6d7960ac 100644 --- a/packages/core-api/src/plugin/Plugin.tsx +++ b/packages/core-api/src/plugin/Plugin.tsx @@ -19,13 +19,18 @@ import { PluginOutput, BackstagePlugin, Extension, + AnyRoutes, + AnyExternalRoutes, } from './types'; import { AnyApiFactory } from '../apis'; -export class PluginImpl implements BackstagePlugin { +export class PluginImpl< + Routes extends AnyRoutes, + ExternalRoutes extends AnyExternalRoutes +> implements BackstagePlugin { private storedOutput?: PluginOutput[]; - constructor(private readonly config: PluginConfig) {} + constructor(private readonly config: PluginConfig) {} getId(): string { return this.config.id; @@ -35,6 +40,14 @@ export class PluginImpl implements BackstagePlugin { return this.config.apis ?? []; } + get routes(): Routes { + return this.config.routes ?? ({} as Routes); + } + + get externalRoutes(): ExternalRoutes { + return this.config.externalRoutes ?? ({} as ExternalRoutes); + } + output(): PluginOutput[] { if (this.storedOutput) { return this.storedOutput; @@ -79,6 +92,11 @@ export class PluginImpl implements BackstagePlugin { } } -export function createPlugin(config: PluginConfig): BackstagePlugin { +export function createPlugin< + Routes extends AnyRoutes = {}, + ExternalRoutes extends AnyExternalRoutes = {} +>( + config: PluginConfig, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-api/src/plugin/collectors.test.tsx b/packages/core-api/src/plugin/collectors.test.tsx index f040cfd433..5baf2539ab 100644 --- a/packages/core-api/src/plugin/collectors.test.tsx +++ b/packages/core-api/src/plugin/collectors.test.tsx @@ -30,7 +30,9 @@ import { import { pluginCollector } from './collectors'; const mockConfig = () => ({ path: '/foo', title: 'Foo' }); -const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; +const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => ( + <>{children} +); const pluginA = createPlugin({ id: 'my-plugin-a' }); const pluginB = createPlugin({ id: 'my-plugin-b' }); @@ -40,19 +42,25 @@ const ref1 = createRouteRef(mockConfig()); const ref2 = createRouteRef(mockConfig()); const Extension1 = pluginA.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref1 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref1, + }), ); const Extension2 = pluginB.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref2 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref2, + }), ); const Extension3 = pluginA.provide( - createComponentExtension({ component: MockComponent }), + createComponentExtension({ component: { sync: MockComponent } }), ); const Extension4 = pluginB.provide( - createComponentExtension({ component: MockComponent }), + createComponentExtension({ component: { sync: MockComponent } }), ); const Extension5 = pluginC.provide( - createComponentExtension({ component: MockComponent }), + createComponentExtension({ component: { sync: MockComponent } }), ); describe('collection', () => { diff --git a/packages/core-api/src/plugin/collectors.ts b/packages/core-api/src/plugin/collectors.ts index 3eadfc0185..b04c7b41c4 100644 --- a/packages/core-api/src/plugin/collectors.ts +++ b/packages/core-api/src/plugin/collectors.ts @@ -34,9 +34,12 @@ import { getComponentData } from '../extensions'; import { createCollector } from '../extensions/traversal'; export const pluginCollector = createCollector( - () => new Set(), + () => new Set>(), (acc, node) => { - const plugin = getComponentData(node, 'core.plugin'); + const plugin = getComponentData>( + node, + 'core.plugin', + ); if (plugin) { acc.add(plugin); } diff --git a/packages/core-api/src/plugin/index.ts b/packages/core-api/src/plugin/index.ts index 79b0575755..bbeeca4824 100644 --- a/packages/core-api/src/plugin/index.ts +++ b/packages/core-api/src/plugin/index.ts @@ -15,4 +15,19 @@ */ export { createPlugin } from './Plugin'; -export * from './types'; +export type { + BackstagePlugin, + Extension, + FeatureFlagOutput, + FeatureFlagsHooks, + LegacyRedirectRouteOutput, + LegacyRouteOutput, + PluginConfig, + PluginHooks, + PluginOutput, + RedirectRouteOutput, + RouteOptions, + RouteOutput, + RoutePath, + RouterHooks, +} from './types'; diff --git a/packages/core-api/src/plugin/types.ts b/packages/core-api/src/plugin/types.ts index dd19948a0a..94bd4e8172 100644 --- a/packages/core-api/src/plugin/types.ts +++ b/packages/core-api/src/plugin/types.ts @@ -17,6 +17,7 @@ import { ComponentType } from 'react'; import { RouteRef } from '../routing'; import { AnyApiFactory } from '../apis/system'; +import { ExternalRouteRef } from '../routing/RouteRef'; export type RouteOptions = { // Whether the route path must match exactly, defaults to true. @@ -67,20 +68,34 @@ export type PluginOutput = | FeatureFlagOutput; export type Extension = { - expose(plugin: BackstagePlugin): T; + expose(plugin: BackstagePlugin): T; }; -export type BackstagePlugin = { +export type AnyRoutes = { [name: string]: RouteRef }; + +export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; + +export type BackstagePlugin< + Routes extends AnyRoutes = {}, + ExternalRoutes extends AnyExternalRoutes = {} +> = { getId(): string; output(): PluginOutput[]; getApis(): Iterable; provide(extension: Extension): T; + routes: Routes; + externalRoutes: ExternalRoutes; }; -export type PluginConfig = { +export type PluginConfig< + Routes extends AnyRoutes, + ExternalRoutes extends AnyExternalRoutes +> = { id: string; apis?: Iterable; register?(hooks: PluginHooks): void; + routes?: Routes; + externalRoutes?: ExternalRoutes; }; export type PluginHooks = { diff --git a/packages/core-api/src/public.ts b/packages/core-api/src/public.ts index 0a30936c52..f91d97c31d 100644 --- a/packages/core-api/src/public.ts +++ b/packages/core-api/src/public.ts @@ -16,6 +16,7 @@ export * from './apis'; export * from './app'; +export * from './extensions'; export * from './icons'; export * from './plugin'; export * from './routing'; diff --git a/packages/core-api/src/routing/RouteRef.ts b/packages/core-api/src/routing/RouteRef.ts index 0fbc57c6f1..f89634e0ec 100644 --- a/packages/core-api/src/routing/RouteRef.ts +++ b/packages/core-api/src/routing/RouteRef.ts @@ -53,3 +53,21 @@ export function createRouteRef< >(config: RouteRefConfig): RouteRef { return new AbsoluteRouteRef(config); } + +const create = Symbol('create-external-route-ref'); + +export class ExternalRouteRef { + static [create]() { + return new ExternalRouteRef(); + } + + private constructor() {} + + toString() { + return `externalRouteRef{}`; + } +} + +export function createExternalRouteRef(): ExternalRouteRef { + return ExternalRouteRef[create](); +} diff --git a/packages/core-api/src/routing/collectors.test.tsx b/packages/core-api/src/routing/collectors.test.tsx index 2595b8c0a0..200846f175 100644 --- a/packages/core-api/src/routing/collectors.test.tsx +++ b/packages/core-api/src/routing/collectors.test.tsx @@ -28,7 +28,9 @@ import { createRoutableExtension } from '../extensions'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; const mockConfig = () => ({ path: '/foo', title: 'Foo' }); -const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; +const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => ( + <>{children} +); const plugin = createPlugin({ id: 'my-plugin' }); @@ -39,19 +41,34 @@ const ref4 = createRouteRef(mockConfig()); const ref5 = createRouteRef(mockConfig()); const Extension1 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref1 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref1, + }), ); const Extension2 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref2 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref2, + }), ); const Extension3 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref3 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref3, + }), ); const Extension4 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref4 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref4, + }), ); const Extension5 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref5 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref5, + }), ); describe('discovery', () => { @@ -188,6 +205,6 @@ describe('discovery', () => { routeParents: routeParentCollector, }, }), - ).toThrow(`Visited element Extension(MockComponent) twice`); + ).toThrow(`Visited element Extension(Component) twice`); }); }); diff --git a/packages/core-api/src/routing/hooks.test.tsx b/packages/core-api/src/routing/hooks.test.tsx index ae1053b58d..3dbeaf8e3e 100644 --- a/packages/core-api/src/routing/hooks.test.tsx +++ b/packages/core-api/src/routing/hooks.test.tsx @@ -35,7 +35,11 @@ import { validateRoutes, RouteFunc, } from './hooks'; -import { createRouteRef } from './RouteRef'; +import { + createRouteRef, + createExternalRouteRef, + ExternalRouteRef, +} from './RouteRef'; import { RouteRef, RouteRefConfig } from './types'; const mockConfig = (extra?: Partial>) => ({ @@ -43,7 +47,9 @@ const mockConfig = (extra?: Partial>) => ({ title: 'Unused', ...extra, }); -const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; +const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => ( + <>{children} +); const plugin = createPlugin({ id: 'my-plugin' }); @@ -52,10 +58,14 @@ const ref2 = createRouteRef(mockConfig({ path: '/wat2' })); const ref3 = createRouteRef(mockConfig({ path: '/wat3' })); const ref4 = createRouteRef(mockConfig({ path: '/wat4' })); const ref5 = createRouteRef(mockConfig({ path: '/wat5' })); +const eRefA = createExternalRouteRef(); +const eRefB = createExternalRouteRef(); +const eRefC = createExternalRouteRef(); const MockRouteSource = (props: { + path?: string; name: string; - routeRef: RouteRef; + routeRef: RouteRef | ExternalRouteRef; params?: T; }) => { try { @@ -75,22 +85,40 @@ const MockRouteSource = (props: { }; const Extension1 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref1 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref1, + }), ); const Extension2 = plugin.provide( - createRoutableExtension({ component: MockRouteSource, mountPoint: ref2 }), + createRoutableExtension({ + component: () => Promise.resolve(MockRouteSource), + mountPoint: ref2, + }), ); const Extension3 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref3 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref3, + }), ); const Extension4 = plugin.provide( - createRoutableExtension({ component: MockRouteSource, mountPoint: ref4 }), + createRoutableExtension({ + component: () => Promise.resolve(MockRouteSource), + mountPoint: ref4, + }), ); const Extension5 = plugin.provide( - createRoutableExtension({ component: MockComponent, mountPoint: ref5 }), + createRoutableExtension({ + component: () => Promise.resolve(MockComponent), + mountPoint: ref5, + }), ); -function withRoutingProvider(root: ReactElement) { +function withRoutingProvider( + root: ReactElement, + routeBindings: [ExternalRouteRef, RouteRef][] = [], +) { const { routePaths, routeParents, routeObjects } = traverseElementTree({ root, discoverers: [childDiscoverer, routeElementDiscoverer], @@ -106,6 +134,7 @@ function withRoutingProvider(root: ReactElement) { routePaths={routePaths} routeParents={routeParents} routeObjects={routeObjects} + routeBindings={new Map(routeBindings)} > {root} @@ -113,26 +142,46 @@ function withRoutingProvider(root: ReactElement) { } describe('discovery', () => { - it('should handle simple routeRef path creation for routeRefs used in other parts of the app', () => { + it('should handle simple routeRef path creation for routeRefs used in other parts of the app', async () => { const root = ( + + + ); - const rendered = render(withRoutingProvider(root)); + const rendered = render( + withRoutingProvider(root, [ + [eRefA, ref3], + [eRefB, ref1], + [eRefC, ref2], + ]), + ); - expect(rendered.getByText('Path at inside: /foo/bar')).toBeInTheDocument(); + await expect( + rendered.findByText('Path at inside: /foo/bar'), + ).resolves.toBeInTheDocument(); + expect( + rendered.getByText('Path at insideExternal: /baz'), + ).toBeInTheDocument(); expect(rendered.getByText('Path at outside: /foo/bar')).toBeInTheDocument(); + expect( + rendered.getByText('Path at outsideExternal1: /foo'), + ).toBeInTheDocument(); + expect( + rendered.getByText('Path at outsideExternal2: /foo/bar'), + ).toBeInTheDocument(); }); - it('should handle routeRefs with parameters', () => { + it('should handle routeRefs with parameters', async () => { const root = ( @@ -155,37 +204,39 @@ describe('discovery', () => { const rendered = render(withRoutingProvider(root)); - expect( - rendered.getByText('Path at inside: /foo/bar/bleb'), - ).toBeInTheDocument(); + await expect( + rendered.findByText('Path at inside: /foo/bar/bleb'), + ).resolves.toBeInTheDocument(); expect( rendered.getByText('Path at outside: /foo/bar/blob'), ).toBeInTheDocument(); }); - it('should handle relative routing within parameterized routePaths', () => { + it('should handle relative routing within parameterized routePaths', async () => { const root = ( - - - - - - - - + + + + + + + + + + ); const rendered = render(withRoutingProvider(root)); - expect( - rendered.getByText('Path at inside: /foo/blob/baz'), - ).toBeInTheDocument(); + await expect( + rendered.findByText('Path at inside: /foo/blob/baz'), + ).resolves.toBeInTheDocument(); }); it('should throw errors for routing to other routeRefs with unsupported parameters', () => { diff --git a/packages/core-api/src/routing/hooks.tsx b/packages/core-api/src/routing/hooks.tsx index 563bc84a76..55fde89de2 100644 --- a/packages/core-api/src/routing/hooks.tsx +++ b/packages/core-api/src/routing/hooks.tsx @@ -17,6 +17,7 @@ import React, { createContext, ReactNode, useContext, useMemo } from 'react'; import { AnyRouteRef, BackstageRouteObject, RouteRef } from './types'; import { generatePath, matchRoutes, useLocation } from 'react-router-dom'; +import { ExternalRouteRef } from './RouteRef'; // The extra TS magic here is to require a single params argument if the RouteRef // had at least one param defined, but require 0 arguments if there are no params defined. @@ -34,12 +35,17 @@ class RouteResolver { private readonly routePaths: Map, private readonly routeParents: Map, private readonly routeObjects: BackstageRouteObject[], + private readonly routeBindings: Map, ) {} resolve( - routeRef: RouteRef, + routeRefOrExternalRouteRef: RouteRef | ExternalRouteRef, sourceLocation: ReturnType, ): RouteFunc { + const routeRef = + this.routeBindings.get(routeRefOrExternalRouteRef) ?? + (routeRefOrExternalRouteRef as RouteRef); + const match = matchRoutes(this.routeObjects, sourceLocation) ?? []; const lastPath = this.routePaths.get(routeRef); @@ -106,7 +112,7 @@ class RouteResolver { const RoutingContext = createContext(undefined); export function useRouteRef( - routeRef: RouteRef, + routeRef: RouteRef | ExternalRouteRef, ): RouteFunc { const sourceLocation = useLocation(); const resolver = useContext(RoutingContext); @@ -126,6 +132,7 @@ type ProviderProps = { routePaths: Map; routeParents: Map; routeObjects: BackstageRouteObject[]; + routeBindings: Map; children: ReactNode; }; @@ -133,9 +140,15 @@ export const RoutingProvider = ({ routePaths, routeParents, routeObjects, + routeBindings, children, }: ProviderProps) => { - const resolver = new RouteResolver(routePaths, routeParents, routeObjects); + const resolver = new RouteResolver( + routePaths, + routeParents, + routeObjects, + routeBindings, + ); return ( {children} diff --git a/packages/core-api/src/routing/index.ts b/packages/core-api/src/routing/index.ts index d682aa9348..3591f299f1 100644 --- a/packages/core-api/src/routing/index.ts +++ b/packages/core-api/src/routing/index.ts @@ -22,3 +22,4 @@ export type { MutableRouteRef, } from './types'; export { createRouteRef } from './RouteRef'; +export { useRouteRef } from './hooks'; diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index aeb1c961b7..d4eb0a0a95 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/core +## 0.4.1 + +### Patch Changes + +- 8ef71ed32: Add a `` component to `@backstage/core`. +- Updated dependencies [7dd2ef7d1] + - @backstage/core-api@0.2.6 + ## 0.4.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 54d4b1a267..3c636a0d80 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core", "description": "Core API used by Backstage plugins and apps", - "version": "0.4.0", + "version": "0.4.1", "private": false, "publishConfig": { "access": "public", @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/core-api": "^0.2.5", + "@backstage/core-api": "^0.2.6", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -65,7 +65,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/core/src/api-wrappers/createApp.tsx b/packages/core/src/api-wrappers/createApp.tsx index c99ba0ed03..9a8f7a36df 100644 --- a/packages/core/src/api-wrappers/createApp.tsx +++ b/packages/core/src/api-wrappers/createApp.tsx @@ -142,6 +142,7 @@ export function createApp(options?: AppOptions) { themes, configLoader, defaultApis, + bindRoutes: options?.bindRoutes, }); app.verify(); diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index b8b630d2e4..8e9b3692af 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/create-app +## 0.2.5 + +### Patch Changes + +- 2783ec018: In the techdocs-backend plugin (`packages/backend/src/plugins/techdocs.ts`), create a publisher using + + ``` + const publisher = Publisher.fromConfig(config, logger, discovery); + ``` + + instead of + + ``` + const publisher = new LocalPublish(logger, discovery); + ``` + + An instance of `publisher` can either be a local filesystem publisher or a Google Cloud Storage publisher. + + Read more about the configs here https://backstage.io/docs/features/techdocs/configuration + (You will also have to update `techdocs.storage.type` to `local` or `googleGcs`. And `techdocs.builder` to either `local` or `external`.) + ## 0.2.4 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 5b7484b575..52691fc2ee 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "Create app package for Backstage", - "version": "0.2.4", + "version": "0.2.5", "private": false, "publishConfig": { "access": "public" @@ -37,28 +37,29 @@ "recursive-readdir": "^2.2.2" }, "devDependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", - "@backstage/cli": "^0.4.1", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", + "@backstage/cli": "^0.4.2", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.0", - "@backstage/plugin-api-docs": "^0.4.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-api-docs": "^0.4.1", "@backstage/plugin-app-backend": "^0.3.3", - "@backstage/plugin-auth-backend": "^0.2.6", - "@backstage/plugin-catalog": "^0.2.6", - "@backstage/plugin-catalog-backend": "^0.4.0", - "@backstage/plugin-circleci": "^0.2.4", + "@backstage/plugin-auth-backend": "^0.2.7", + "@backstage/plugin-catalog": "^0.2.7", + "@backstage/plugin-catalog-backend": "^0.5.0", + "@backstage/plugin-circleci": "^0.2.5", "@backstage/plugin-explore": "^0.2.2", - "@backstage/plugin-github-actions": "^0.2.4", - "@backstage/plugin-lighthouse": "^0.2.5", + "@backstage/plugin-github-actions": "^0.2.5", + "@backstage/plugin-lighthouse": "^0.2.6", "@backstage/plugin-proxy-backend": "^0.2.3", - "@backstage/plugin-register-component": "^0.2.4", + "@backstage/plugin-register-component": "^0.2.5", "@backstage/plugin-rollbar-backend": "^0.1.5", - "@backstage/plugin-scaffolder": "^0.3.3", - "@backstage/plugin-scaffolder-backend": "^0.3.4", + "@backstage/plugin-scaffolder": "^0.3.4", + "@backstage/plugin-search": "^0.2.4", + "@backstage/plugin-scaffolder-backend": "^0.3.5", "@backstage/plugin-tech-radar": "^0.3.1", - "@backstage/plugin-techdocs": "^0.4.0", - "@backstage/plugin-techdocs-backend": "^0.3.2", + "@backstage/plugin-techdocs": "^0.5.0", + "@backstage/plugin-techdocs-backend": "^0.4.0", "@backstage/plugin-user-settings": "^0.2.3", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 84f015509c..df8b9c01ea 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -48,6 +48,7 @@ import { version as pluginRegisterComponent } from '@backstage/plugin-register-c import { version as pluginRollbarBackend } from '@backstage/plugin-rollbar-backend/package.json'; import { version as pluginScaffolder } from '@backstage/plugin-scaffolder/package.json'; import { version as pluginScaffolderBackend } from '@backstage/plugin-scaffolder-backend/package.json'; +import { version as pluginSearch } from '@backstage/plugin-search/package.json'; import { version as pluginTechRadar } from '@backstage/plugin-tech-radar/package.json'; import { version as pluginTechdocs } from '@backstage/plugin-techdocs/package.json'; import { version as pluginTechdocsBackend } from '@backstage/plugin-techdocs-backend/package.json'; @@ -75,6 +76,7 @@ export const packageVersions = { '@backstage/plugin-rollbar-backend': pluginRollbarBackend, '@backstage/plugin-scaffolder': pluginScaffolder, '@backstage/plugin-scaffolder-backend': pluginScaffolderBackend, + '@backstage/plugin-search': pluginSearch, '@backstage/plugin-tech-radar': pluginTechRadar, '@backstage/plugin-techdocs': pluginTechdocs, '@backstage/plugin-techdocs-backend': pluginTechdocsBackend, diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index f284f2da0f..1746f171c9 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -19,6 +19,7 @@ "@backstage/plugin-tech-radar": "^{{version '@backstage/plugin-tech-radar'}}", "@backstage/plugin-github-actions": "^{{version '@backstage/plugin-github-actions'}}", "@backstage/plugin-user-settings": "^{{version '@backstage/plugin-user-settings'}}", + "@backstage/plugin-search": "^{{version '@backstage/plugin-search'}}", "@backstage/test-utils": "^{{version '@backstage/test-utils'}}", "@backstage/theme": "^{{version '@backstage/theme'}}", "history": "^5.0.0", diff --git a/packages/create-app/templates/default-app/packages/app/src/App.tsx b/packages/create-app/templates/default-app/packages/app/src/App.tsx index 4f5c4edea0..2e250a94a1 100644 --- a/packages/create-app/templates/default-app/packages/app/src/App.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/App.tsx @@ -14,6 +14,7 @@ import { Router as CatalogRouter } from '@backstage/plugin-catalog'; import { Router as DocsRouter } from '@backstage/plugin-techdocs'; import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component'; import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; +import { SearchPage as SearchRouter } from '@backstage/plugin-search'; import { EntityPage } from './components/catalog/EntityPage'; @@ -54,6 +55,10 @@ const App = () => ( path="/register-component" element={} /> + } + /> {deprecatedAppRoutes} diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx index db73e706b1..a5595e2c09 100644 --- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx @@ -20,10 +20,12 @@ import { SidebarContext, SidebarSpace, } from '@backstage/core'; +import { SidebarSearch } from '@backstage/plugin-search'; export const AppSidebar = () => ( + {/* Global nav, not org-specific */} diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index f080685efe..5559c5230d 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/integration +## 0.1.4 + +### Patch Changes + +- 1d1c2860f: Implement readTree on BitBucketUrlReader and getBitbucketDownloadUrl +- 4eafdec4a: Introduce readTree method for GitLab URL Reader +- 178e09323: Validate that integration config contains a valid host + ## 0.1.3 ### Patch Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 78112de311..fe5bd60905 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "0.1.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "dependencies": { "@backstage/config": "^0.1.2", "cross-fetch": "^3.0.6", - "git-url-parse": "^11.4.0" + "git-url-parse": "^11.4.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/test-utils": "^0.1.5", "@types/jest": "^26.0.7", "msw": "^0.21.2" diff --git a/packages/integration/src/azure/AzureIntegration.test.ts b/packages/integration/src/azure/AzureIntegration.test.ts index aec37ce905..4a0c32badb 100644 --- a/packages/integration/src/azure/AzureIntegration.test.ts +++ b/packages/integration/src/azure/AzureIntegration.test.ts @@ -20,21 +20,16 @@ import { AzureIntegration } from './AzureIntegration'; describe('AzureIntegration', () => { it('has a working factory', () => { const integrations = AzureIntegration.factory({ - config: ConfigReader.fromConfigs([ - { - context: '', - data: { - integrations: { - azure: [ - { - host: 'h.com', - token: 'token', - }, - ], + config: new ConfigReader({ + integrations: { + azure: [ + { + host: 'h.com', + token: 'token', }, - }, + ], }, - ]), + }), }); expect(integrations.length).toBe(2); // including default expect(integrations[0].predicate(new URL('https://h.com/a'))).toBe(true); diff --git a/packages/integration/src/azure/config.test.ts b/packages/integration/src/azure/config.test.ts index 0b943f2081..eed88f09f6 100644 --- a/packages/integration/src/azure/config.test.ts +++ b/packages/integration/src/azure/config.test.ts @@ -23,7 +23,7 @@ import { describe('readAzureIntegrationConfig', () => { function buildConfig(data: Partial): Config { - return ConfigReader.fromConfigs([{ context: '', data }]); + return new ConfigReader(data); } it('reads all values', () => { @@ -60,9 +60,7 @@ describe('readAzureIntegrationConfig', () => { describe('readAzureIntegrationConfigs', () => { function buildConfig(data: Partial[]): Config[] { - return data.map(item => - ConfigReader.fromConfigs([{ context: '', data: item }]), - ); + return data.map(item => new ConfigReader(item)); } it('reads all values', () => { diff --git a/packages/integration/src/bitbucket/BitbucketIntegration.test.ts b/packages/integration/src/bitbucket/BitbucketIntegration.test.ts index 174b6ab232..87dbac2263 100644 --- a/packages/integration/src/bitbucket/BitbucketIntegration.test.ts +++ b/packages/integration/src/bitbucket/BitbucketIntegration.test.ts @@ -20,24 +20,19 @@ import { BitbucketIntegration } from './BitbucketIntegration'; describe('BitbucketIntegration', () => { it('has a working factory', () => { const integrations = BitbucketIntegration.factory({ - config: ConfigReader.fromConfigs([ - { - context: '', - data: { - integrations: { - bitbucket: [ - { - host: 'h.com', - apiBaseUrl: 'a', - token: 't', - username: 'u', - appPassword: 'p', - }, - ], + config: new ConfigReader({ + integrations: { + bitbucket: [ + { + host: 'h.com', + apiBaseUrl: 'a', + token: 't', + username: 'u', + appPassword: 'p', }, - }, + ], }, - ]), + }), }); expect(integrations.length).toBe(2); // including default expect(integrations[0].predicate(new URL('https://h.com/a'))).toBe(true); diff --git a/packages/integration/src/bitbucket/config.test.ts b/packages/integration/src/bitbucket/config.test.ts index 775a8b7d2d..9106afbe4f 100644 --- a/packages/integration/src/bitbucket/config.test.ts +++ b/packages/integration/src/bitbucket/config.test.ts @@ -23,7 +23,7 @@ import { describe('readBitbucketIntegrationConfig', () => { function buildConfig(data: Partial): Config { - return ConfigReader.fromConfigs([{ context: '', data }]); + return new ConfigReader(data); } it('reads all values', () => { @@ -83,9 +83,7 @@ describe('readBitbucketIntegrationConfig', () => { describe('readBitbucketIntegrationConfigs', () => { function buildConfig(data: Partial[]): Config[] { - return data.map(item => - ConfigReader.fromConfigs([{ context: '', data: item }]), - ); + return data.map(item => new ConfigReader(item)); } it('reads all values', () => { diff --git a/packages/integration/src/bitbucket/core.test.ts b/packages/integration/src/bitbucket/core.test.ts index c6fe5ddf6c..39707976fe 100644 --- a/packages/integration/src/bitbucket/core.test.ts +++ b/packages/integration/src/bitbucket/core.test.ts @@ -144,8 +144,7 @@ describe('bitbucket core', () => { }; worker.use( rest.get( - // TODO: Change URL to https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default when git-url-parse bug is fixed - 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/projects/backstage/repos/mock/repos/browse/branches/default', + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default', (_, res, ctx) => res( ctx.status(200), @@ -159,13 +158,13 @@ describe('bitbucket core', () => { apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0', }; const result = await getBitbucketDownloadUrl( - 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse?at=main', + 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse', config, ); - expect(new URL(result).searchParams.get('format')).toEqual('zip'); - expect(new URL(result).searchParams.get('at')).toEqual('main'); - expect(new URL(result).searchParams.get('prefix')).not.toBeNull(); - expect(new URL(result).searchParams.get('path')).toBeNull(); + + expect(result).toEqual( + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/archive?format=zip&at=main&prefix=backstage-mock', + ); }); it('get by branch for Bitbucket Server', async () => { diff --git a/packages/integration/src/github/GitHubIntegration.test.ts b/packages/integration/src/github/GitHubIntegration.test.ts index 3383c9ebe7..0c326d81cd 100644 --- a/packages/integration/src/github/GitHubIntegration.test.ts +++ b/packages/integration/src/github/GitHubIntegration.test.ts @@ -20,23 +20,18 @@ import { GitHubIntegration } from './GitHubIntegration'; describe('GitHubIntegration', () => { it('has a working factory', () => { const integrations = GitHubIntegration.factory({ - config: ConfigReader.fromConfigs([ - { - context: '', - data: { - integrations: { - github: [ - { - host: 'h.com', - apiBaseUrl: 'a', - rawBaseUrl: 'r', - token: 't', - }, - ], + config: new ConfigReader({ + integrations: { + github: [ + { + host: 'h.com', + apiBaseUrl: 'a', + rawBaseUrl: 'r', + token: 't', }, - }, + ], }, - ]), + }), }); expect(integrations.length).toBe(2); // including default expect(integrations[0].predicate(new URL('https://h.com/a'))).toBe(true); diff --git a/packages/integration/src/github/config.test.ts b/packages/integration/src/github/config.test.ts index d33cffb7be..bcac7dc82c 100644 --- a/packages/integration/src/github/config.test.ts +++ b/packages/integration/src/github/config.test.ts @@ -23,7 +23,7 @@ import { describe('readGitHubIntegrationConfig', () => { function buildConfig(provider: Partial) { - return ConfigReader.fromConfigs([{ context: '', data: provider }]); + return new ConfigReader(provider); } it('reads all values', () => { @@ -80,9 +80,7 @@ describe('readGitHubIntegrationConfigs', () => { function buildConfig( providers: Partial[], ): Config[] { - return providers.map(provider => - ConfigReader.fromConfigs([{ context: '', data: provider }]), - ); + return providers.map(provider => new ConfigReader(provider)); } it('reads all values', () => { diff --git a/packages/integration/src/gitlab/GitLabIntegration.test.ts b/packages/integration/src/gitlab/GitLabIntegration.test.ts index 4a23f55816..260afd23d8 100644 --- a/packages/integration/src/gitlab/GitLabIntegration.test.ts +++ b/packages/integration/src/gitlab/GitLabIntegration.test.ts @@ -20,21 +20,16 @@ import { GitLabIntegration } from './GitLabIntegration'; describe('GitLabIntegration', () => { it('has a working factory', () => { const integrations = GitLabIntegration.factory({ - config: ConfigReader.fromConfigs([ - { - context: '', - data: { - integrations: { - gitlab: [ - { - host: 'h.com', - token: 't', - }, - ], + config: new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'h.com', + token: 't', }, - }, + ], }, - ]), + }), }); expect(integrations.length).toBe(2); // including default expect(integrations[0].predicate(new URL('https://h.com/a'))).toBe(true); diff --git a/packages/integration/src/gitlab/config.test.ts b/packages/integration/src/gitlab/config.test.ts index 9998a530c6..e817465b83 100644 --- a/packages/integration/src/gitlab/config.test.ts +++ b/packages/integration/src/gitlab/config.test.ts @@ -23,7 +23,7 @@ import { describe('readGitLabIntegrationConfig', () => { function buildConfig(data: Partial): Config { - return ConfigReader.fromConfigs([{ context: '', data }]); + return new ConfigReader(data); } it('reads all values', () => { @@ -41,7 +41,10 @@ describe('readGitLabIntegrationConfig', () => { it('inserts the defaults if missing', () => { const output = readGitLabIntegrationConfig(buildConfig({})); - expect(output).toEqual({ host: 'gitlab.com' }); + expect(output).toEqual({ + host: 'gitlab.com', + apiBaseUrl: 'gitlab.com/api/v4', + }); }); it('rejects funky configs', () => { @@ -60,9 +63,7 @@ describe('readGitLabIntegrationConfig', () => { describe('readGitLabIntegrationConfigs', () => { function buildConfig(data: Partial[]): Config[] { - return data.map(item => - ConfigReader.fromConfigs([{ context: '', data: item }]), - ); + return data.map(item => new ConfigReader(item)); } it('reads all values', () => { diff --git a/packages/integration/src/gitlab/config.ts b/packages/integration/src/gitlab/config.ts index a38312d01a..2d9f4b39ab 100644 --- a/packages/integration/src/gitlab/config.ts +++ b/packages/integration/src/gitlab/config.ts @@ -18,6 +18,7 @@ import { Config } from '@backstage/config'; import { isValidHost } from '../helpers'; const GITLAB_HOST = 'gitlab.com'; +const GITLAB_API_BASE_URL = 'gitlab.com/api/v4'; /** * The configuration parameters for a single GitLab integration. @@ -28,6 +29,17 @@ export type GitLabIntegrationConfig = { */ host: string; + /** + * The base URL of the API of this provider, e.g. "https://gitlab.com/api/v4", + * with no trailing slash. + * + * May be omitted specifically for GitLab; then it will be deduced. + * + * The API will always be preferred if both its base URL and a token are + * present. + */ + apiBaseUrl?: string; + /** * The authorization token to use for requests this provider. * @@ -45,6 +57,7 @@ export function readGitLabIntegrationConfig( config: Config, ): GitLabIntegrationConfig { const host = config.getOptionalString('host') ?? GITLAB_HOST; + let apiBaseUrl = config.getOptionalString('apiBaseUrl'); const token = config.getOptionalString('token'); if (!isValidHost(host)) { @@ -53,7 +66,12 @@ export function readGitLabIntegrationConfig( ); } - return { host, token }; + if (apiBaseUrl) { + apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); + } else if (host === GITLAB_HOST) { + apiBaseUrl = GITLAB_API_BASE_URL; + } + return { host, token, apiBaseUrl }; } /** diff --git a/packages/storybook/.storybook/apis.js b/packages/storybook/.storybook/apis.js index 878256ff5c..128ccfc67a 100644 --- a/packages/storybook/.storybook/apis.js +++ b/packages/storybook/.storybook/apis.js @@ -26,7 +26,7 @@ import { const builder = ApiRegistry.builder(); -builder.add(configApiRef, ConfigReader.fromConfigs([])); +builder.add(configApiRef, new ConfigReader({})); const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); diff --git a/packages/storybook/.storybook/main.js b/packages/storybook/.storybook/main.js index 136b3945da..77bafdd231 100644 --- a/packages/storybook/.storybook/main.js +++ b/packages/storybook/.storybook/main.js @@ -22,7 +22,7 @@ module.exports = { // Remove the default babel-loader for js files, we're using sucrase instead const [jsLoader] = config.module.rules.splice(0, 1); - if (jsLoader.use[0].loader !== 'babel-loader') { + if (!jsLoader.use[0].loader.includes('babel-loader')) { throw new Error( `Unexpected loader removed from storybook config, ${jsLoader.use[0].loader}`, ); diff --git a/packages/storybook/package.json b/packages/storybook/package.json index f143596a9a..01aabac0de 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -17,11 +17,11 @@ "@backstage/theme": "^0.2.0" }, "devDependencies": { - "@storybook/addon-actions": "^6.0.21", - "@storybook/addon-links": "^6.0.21", - "@storybook/addon-storysource": "^6.0.21", - "@storybook/addons": "^6.0.21", - "@storybook/react": "^6.0.21", - "storybook-dark-mode": "^1.0.2" + "@storybook/addon-actions": "^6.1.11", + "@storybook/addon-links": "^6.1.11", + "@storybook/addon-storysource": "^6.1.11", + "@storybook/addons": "^6.1.11", + "@storybook/react": "^6.1.11", + "storybook-dark-mode": "^1.0.3" } } diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md new file mode 100644 index 0000000000..af3da478a5 --- /dev/null +++ b/packages/techdocs-common/CHANGELOG.md @@ -0,0 +1,55 @@ +# @backstage/techdocs-common + +## 0.2.0 + +### Minor Changes + +- dae4f3983: _Breaking changes_ + + 1. Added option to use Google Cloud Storage as a choice to store the static generated files for TechDocs. + It can be configured using `techdocs.publisher.type` option in `app-config.yaml`. + Step-by-step guide to configure GCS is available here https://backstage.io/docs/features/techdocs/using-cloud-storage + Set `techdocs.publisher.type` to `'local'` if you want to continue using local filesystem to store TechDocs files. + + 2. `techdocs.builder` is now required and can be set to `'local'` or `'external'`. (Set it to `'local'` for now, since CI/CD build + workflow for TechDocs will be available soon (in few weeks)). + If builder is set to 'local' and you open a TechDocs page, `techdocs-backend` will try to generate the docs, publish to storage and + show the generated docs afterwords. + If builder is set to `'external'`, `techdocs-backend` will only fetch the docs and will NOT try to generate and publish. In this case of `'external'`, + we assume that docs are being built in the CI/CD pipeline of the repository. + TechDocs will not assume a default value for `techdocs.builder`. It is better to explicitly define it in the `app-config.yaml`. + + 3. When configuring TechDocs in your backend, there is a difference in how a new publisher is created. + + ``` + --- const publisher = new LocalPublish(logger, discovery); + +++ const publisher = Publisher.fromConfig(config, logger, discovery); + ``` + + Based on the config `techdocs.publisher.type`, the publisher could be either Local publisher or Google Cloud Storage publisher. + + 4. `techdocs.storageUrl` is now a required config. Should be `http://localhost:7000/api/techdocs/static/docs` in most setups. + + 5. Parts of `@backstage/plugin-techdocs-backend` have been moved to a new package `@backstage/techdocs-common` to generate docs. Also to publish docs + to-and-fro between TechDocs and a storage (either local or external). However, a Backstage app does NOT need to import the `techdocs-common` package - + app should only import `@backstage/plugin-techdocs` and `@backstage/plugin-techdocs-backend`. + + _Patch changes_ + + 1. See all of TechDocs config options and its documentation https://backstage.io/docs/features/techdocs/configuration + + 2. Logic about serving static files and metadata retrieval have been abstracted away from the router in `techdocs-backend` to the instance of publisher. + + 3. Removed Material UI Spinner from TechDocs header. Spinners cause unnecessary UX distraction. + Case 1 (when docs are built and are to be served): Spinners appear for a split second before the name of site shows up. This unnecessarily distracts eyes because spinners increase the size of the Header. A dot (.) would do fine. Definitely more can be done. + Case 2 (when docs are being generated): There is already a linear progress bar (which is recommended in Storybook). + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index 4bda9f768a..d0c09919a0 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.1.1", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -36,8 +36,8 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@google-cloud/storage": "^5.6.0", "@types/dockerode": "^3.2.1", @@ -46,18 +46,20 @@ "dockerode": "^3.2.1", "express": "^4.17.1", "fs-extra": "^9.0.1", - "git-url-parse": "^11.4.0", + "git-url-parse": "^11.4.3", "js-yaml": "^3.14.0", + "mime-types": "^2.1.27", "mock-fs": "^4.13.0", "nodegit": "^0.27.0", "recursive-readdir": "^2.2.2", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@types/fs-extra": "^9.0.5", "@types/git-url-parse": "^9.0.0", "@types/js-yaml": "^3.12.5", + "@types/mime-types": "^2.1.0", "@types/mock-fs": "^4.13.0", "@types/nodegit": "^0.26.12", "@types/recursive-readdir": "^2.2.0" diff --git a/packages/techdocs-common/src/stages/generate/generators.test.ts b/packages/techdocs-common/src/stages/generate/generators.test.ts index 7f4a964ec7..3b59d6d007 100644 --- a/packages/techdocs-common/src/stages/generate/generators.test.ts +++ b/packages/techdocs-common/src/stages/generate/generators.test.ts @@ -39,10 +39,7 @@ describe('generators', () => { it('should return correct registered generator', async () => { const generators = new Generators(); - const techdocs = new TechdocsGenerator( - logger, - ConfigReader.fromConfigs([]), - ); + const techdocs = new TechdocsGenerator(logger, new ConfigReader({})); generators.register('techdocs', techdocs); diff --git a/packages/techdocs-common/src/stages/publish/googleStorage.test.ts b/packages/techdocs-common/src/stages/publish/googleStorage.test.ts index 2268ea3fcc..43375b72d0 100644 --- a/packages/techdocs-common/src/stages/publish/googleStorage.test.ts +++ b/packages/techdocs-common/src/stages/publish/googleStorage.test.ts @@ -38,24 +38,19 @@ jest.spyOn(logger, 'info').mockReturnValue(logger); let publisher: PublisherBase; beforeEach(() => { - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - requestUrl: 'http://localhost:7000', - publisher: { - type: 'googleGcs', - googleGcs: { - credentials: '{}', - projectId: 'gcp-project-id', - bucketName: 'bucketName', - }, - }, + const mockConfig = new ConfigReader({ + techdocs: { + requestUrl: 'http://localhost:7000', + publisher: { + type: 'googleGcs', + googleGcs: { + credentials: '{}', + projectId: 'gcp-project-id', + bucketName: 'bucketName', }, }, }, - ]); + }); publisher = GoogleGCSPublish.fromConfig(mockConfig, logger); }); diff --git a/packages/techdocs-common/src/stages/publish/googleStorage.ts b/packages/techdocs-common/src/stages/publish/googleStorage.ts index 5f8dc6a3fc..b33e2bfbe0 100644 --- a/packages/techdocs-common/src/stages/publish/googleStorage.ts +++ b/packages/techdocs-common/src/stages/publish/googleStorage.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import path from 'path'; import express from 'express'; import { Storage, @@ -167,7 +168,7 @@ export class GoogleGCSPublish implements PublisherBase { const filePath = req.path.replace(/^\//, ''); // Files with different extensions (CSS, HTML) need to be served with different headers - const fileExtension = filePath.split('.')[filePath.split('.').length - 1]; + const fileExtension = path.extname(filePath); const responseHeaders = getHeadersForFileExtension(fileExtension); const fileStreamChunks: Array = []; diff --git a/packages/techdocs-common/src/stages/publish/helpers.test.ts b/packages/techdocs-common/src/stages/publish/helpers.test.ts index e4f0c12b79..3b01f5ac43 100644 --- a/packages/techdocs-common/src/stages/publish/helpers.test.ts +++ b/packages/techdocs-common/src/stages/publish/helpers.test.ts @@ -17,29 +17,25 @@ import mockFs from 'mock-fs'; import { getFileTreeRecursively, getHeadersForFileExtension } from './helpers'; describe('getHeadersForFileExtension', () => { - it('returns correct header for default extensions', () => { - const headers = getHeadersForFileExtension('xyz'); - const expectedHeaders = { - 'Content-Type': 'text/plain', - }; - expect(headers).toEqual(expectedHeaders); - }); + const correctMapOfExtensions = [ + ['.html', 'text/html; charset=utf-8'], + ['.css', 'text/css; charset=utf-8'], + ['.png', 'image/png'], + ['.jpg', 'image/jpeg'], + ['.jpeg', 'image/jpeg'], + ['.svg', 'image/svg+xml'], + ['.json', 'application/json; charset=utf-8'], + ['.this-in-not-an-extension', 'text/plain; charset=utf-8'], + ]; - it('returns correct header for html', () => { - const headers = getHeadersForFileExtension('html'); - const expectedHeaders = { - 'Content-Type': 'text/html; charset=UTF-8', - }; - expect(headers).toEqual(expectedHeaders); - }); - - it('returns correct header for css', () => { - const headers = getHeadersForFileExtension('css'); - const expectedHeaders = { - 'Content-Type': 'text/css; charset=UTF-8', - }; - expect(headers).toEqual(expectedHeaders); - }); + test.each(correctMapOfExtensions)( + 'check content-type for %s extension', + (extension, expectedContentType) => { + const headers = getHeadersForFileExtension(extension); + expect(headers).toHaveProperty('Content-Type'); + expect(headers['Content-Type'].toLowerCase()).toBe(expectedContentType); + }, + ); }); describe('getFileTreeRecursively', () => { diff --git a/packages/techdocs-common/src/stages/publish/helpers.ts b/packages/techdocs-common/src/stages/publish/helpers.ts index 38ff27e0a0..138ec611e0 100644 --- a/packages/techdocs-common/src/stages/publish/helpers.ts +++ b/packages/techdocs-common/src/stages/publish/helpers.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import mime from 'mime-types'; import recursiveReadDir from 'recursive-readdir'; export type responseHeadersType = { @@ -22,32 +23,15 @@ export type responseHeadersType = { /** * Some files need special headers to be used correctly by the frontend. This function * generates headers in the response to those file requests. - * @param {string} fileExtension html, css, js etc. + * @param {string} fileExtension .html, .css, .js, .png etc. */ export const getHeadersForFileExtension = ( fileExtension: string, ): responseHeadersType => { - const headersCommon = { - 'Content-Type': 'text/plain', - }; - const headersHTML = { - ...headersCommon, - 'Content-Type': 'text/html; charset=UTF-8', - }; - - const headersCSS = { - ...headersCommon, - 'Content-Type': 'text/css; charset=UTF-8', - }; - - switch (fileExtension) { - case 'html': - return headersHTML; - case 'css': - return headersCSS; - default: - return headersCommon; - } + return { + 'Content-Type': + mime.contentType(fileExtension) || 'text/plain; charset=utf-8', + } as responseHeadersType; }; /** diff --git a/packages/techdocs-common/src/stages/publish/local.test.ts b/packages/techdocs-common/src/stages/publish/local.test.ts index 665ba28c52..efd56285ef 100644 --- a/packages/techdocs-common/src/stages/publish/local.test.ts +++ b/packages/techdocs-common/src/stages/publish/local.test.ts @@ -63,17 +63,12 @@ describe('local publisher', () => { getExternalBaseUrl: jest.fn(), }; - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - requestUrl: 'http://localhost:7000', - storageUrl: 'http://localhost:7000/static/docs', - }, - }, + const mockConfig = new ConfigReader({ + techdocs: { + requestUrl: 'http://localhost:7000', + storageUrl: 'http://localhost:7000/static/docs', }, - ]); + }); const publisher = new LocalPublish(mockConfig, logger, testDiscovery); const mockEntity = createMockEntity(); diff --git a/packages/techdocs-common/src/stages/publish/publish.test.ts b/packages/techdocs-common/src/stages/publish/publish.test.ts index 244a606129..dbced6db29 100644 --- a/packages/techdocs-common/src/stages/publish/publish.test.ts +++ b/packages/techdocs-common/src/stages/publish/publish.test.ts @@ -30,59 +30,44 @@ const testDiscovery: jest.Mocked = { describe('Publisher', () => { it('should create local publisher by default', () => { - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - requestUrl: 'http://localhost:7000', - }, - }, + const mockConfig = new ConfigReader({ + techdocs: { + requestUrl: 'http://localhost:7000', }, - ]); + }); const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery); expect(publisher).toBeInstanceOf(LocalPublish); }); it('should create local publisher from config', () => { - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - requestUrl: 'http://localhost:7000', - publisher: { - type: 'local', - }, - }, + const mockConfig = new ConfigReader({ + techdocs: { + requestUrl: 'http://localhost:7000', + publisher: { + type: 'local', }, }, - ]); + }); const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery); expect(publisher).toBeInstanceOf(LocalPublish); }); it('should create google gcs publisher from config', () => { - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - requestUrl: 'http://localhost:7000', - publisher: { - type: 'googleGcs', - googleGcs: { - credentials: '{}', - projectId: 'gcp-project-id', - bucketName: 'bucketName', - }, - }, + const mockConfig = new ConfigReader({ + techdocs: { + requestUrl: 'http://localhost:7000', + publisher: { + type: 'googleGcs', + googleGcs: { + credentials: '{}', + projectId: 'gcp-project-id', + bucketName: 'bucketName', }, }, }, - ]); + }); const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery); expect(publisher).toBeInstanceOf(GoogleGCSPublish); diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 22bc8ceee4..1f6c7622b8 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -80,6 +80,7 @@ export function wrapInTestApp( }, ], defaultApis: mockApis, + bindRoutes: () => {}, }); let Wrapper: ComponentType; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 53e1da905b..dc1c38ef49 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-api-docs +## 0.4.1 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.4.0 ### Minor Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 944903067b..7346722550 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.4.0", + "version": "0.4.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@kyma-project/asyncapi-react": "^0.14.2", "@material-icons/font": "^1.0.2", @@ -49,7 +49,7 @@ "swagger-ui-react": "^3.37.2" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index d0e0b63706..f011d224b4 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-auth-backend +## 0.2.7 + +### Patch Changes + +- 7b15cc271: Added configuration schema for the commonly used properties +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 + - @backstage/catalog-client@0.3.4 + ## 0.2.6 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index a31460fea0..c55d4e508f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-client": "^0.3.3", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-client": "^0.3.4", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -64,7 +64,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 43a07252b8..95fea0ef3e 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-catalog-backend +## 0.5.0 + +### Minor Changes + +- 6b37c95bf: Write relations directly as part of batch add / update of entities. + + Slight change of the `CommonDatabase` contract: + + ## `addEntity` removed + + This method was unused by the core, and rendered unnecessary when `addEntities` + exists. + + If you were a user of `addEntity`, please call `addEntities` instead, with an + array of one element. + + ## `DbEntityRequest` has a new field `relations` + + This is the structure that is passed to `addEntities` and `updateEntity`. It + used to be the case that you needed to call `setRelations` separately, but now + this instead happens directly when you call `addEntities` or `updateEntity`. + + If you were using `addEntities` or `updateEntity` directly, please adapt your + code to add the `relations` array to each request. If you were calling + `setRelations` separately next to these methods, you no longer need to do so, + after adding the relations to the `DbEntityRequest`s. + +- ac3560b42: Remove `implementsApis` from `Component` entities. Deprecation happened in [#3449](https://github.com/backstage/backstage/pull/3449). + Use `providesApis` instead. + +### Patch Changes + +- c6eeefa35: Add support for Github Enterprise in GitHubOrgReaderProcessor so you can properly ingest users of a GHE organization. +- fb386b760: Break the refresh loop into several smaller transactions +- 7c3ffc0cd: Support `profile` of groups including `displayName`, `email`, and `picture` in + `LdapOrgReaderProcessor`. The source fields for them can be configured in the + `ldapOrg` provider. +- e7496dc3e: Break out GithubOrgReaderProcessor config into its own file for consistency with the other org processors. +- 8dd0a906d: Support `profile` of groups including `displayName` and `picture` in + `GithubOrgReaderProcessor`. Fixes the import of `description` for groups. +- 8c31c681c: Batch the writing of statuses after refreshes. This reduced the runtime on sqlite from 16s to 0.2s, and on pg from 60s to 1s on my machine, for the huge LDAP set. +- 7b98e7fee: Add index to foreign key columns. Postgres (and others) do not do this on the "source" side of a foreign key relation, which was what led to the slowness on large datasets. The full LDAP dataset ingestion now takes two minutes, which is not optimal yet but still a huge improvement over before when it basically never finished :) +- 0097057ed: Support `profile` of groups including `displayName` and `email` in + `MicrosoftGraphOrgReaderProcessor`. Importing `picture` doesn't work yet, as + the Microsoft Graph API does not expose them correctly. +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 + ## 0.4.0 ### Minor Changes diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts new file mode 100644 index 0000000000..54427eae36 --- /dev/null +++ b/plugins/catalog-backend/config.d.ts @@ -0,0 +1,242 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonValue } from '@backstage/config'; + +export interface Config { + /** Configuration options for the catalog plugin */ + catalog?: { + /** + * Rules to apply to catalog entities - accepts an array of objects with below attributes + */ + rules?: Array<{ + /** + * attr: 'allow' - accepts an array of string. e.g. [Component, API, Group, User, Template, Location] + */ + allow: Array; + /** + * opt-attr: 'locations' - accepts an array of key, value pair objects. + * keys: 'target', 'type' + * e.g.[{type: url, target: https://github.com}] + * + */ + locations?: Array<{ [key: string]: string }>; + }>; + /** + * List of processor options and attributes + */ + processors?: { + /** + * Github processor configuration + */ + githubOrg?: { + /** + * attr: 'providers' - accepts an array of objects with below attributes + */ + providers: Array<{ + /** + * attr: 'target' - accepts url string + * e.g. https://ghe.example.net + */ + target: string; + /** + * opt-attr: 'apiBaseUrl' - accepts baseurl string + * e.g. https://ghe.example.net/api + */ + apiBaseUrl?: string; + /** + * opt-attr: 'token' - secret token to authenticate + * e.g. {"$env": "GITHUB_TOKEN"} + * @visibility secret + * */ + token?: string; + }>; + }; + /** + * LdapOrg processor configuration + */ + ldapOrg?: { + /** + * attr: 'providers' - accepts an array of objects with below attributes + */ + providers: { + /** + * attr: 'target' - accepts url string e.g. ldaps://ds.example.net + */ + target: string; + /** + * The settings to use for the a command + * opt-attr: 'bind' - accepts key value pair object + * e.g. {"dn": "uid=ldap-reader-user","secret": {"$secret": {"env": "LDAP_SECRET"}}} + */ + bind?: { + /** + * attr: 'dn' - accepts string with ldap related parameters + * e.g. "dn": "uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * secret used to authenticate. + * e.g. {"$secret": {"env": "LDAP_SECRET"} + * @visibility secret + * */ + secret: Object; + }; + /** + * The settings that govern the reading and interpretation of users. + * attr: 'users' - accepts key value pair object + */ + users: { + /** + * attr: 'dn' - accepts string with user governing parameters + * e.g. "dn": "ou=people,ou=example,dc=example,dc=net" + */ + + dn: string; + /** + * attr: 'options' - accepts an object of key value pair + * keys: 'scope', 'filter', 'attributes', 'sizeLimit', 'timeLimit', 'derefAliases', 'typesOnly', 'paged' + */ + options: { [key: string]: string | boolean | number }; + /** + * opt-attr: 'set - accepts an object of key value pair + * keys: 'path', 'value' + */ + set?: { [key: string]: string | JsonValue }; + /** + * attr: 'map' - accepts an object og key value pair + * keys: 'rdn', 'name', 'description', 'displayName', 'email', 'picture', 'memberOf' + */ + map: { [key: string]: string }; + }; + /** + * The settings that govern the reading and interpretation of groups. + * attr: 'groups' - accepts key value pair object + */ + groups: { + /** + * attr: 'dn' - accepts string with user governing parameters + * e.g. "dn": "ou=people,ou=example,dc=example,dc=net" + */ + + dn: string; + /** + * attr: 'options' - accepts an object of key value pair + * keys: 'scope', 'filter', 'attributes', 'sizeLimit', 'timeLimit', 'derefAliases', 'typesOnly', 'paged' + */ + options: { [key: string]: string | boolean | number }; + /** + * opt-attr: 'set - accepts an object of key value pair + * keys: 'path', 'value' + */ + set?: { [key: string]: string | JsonValue }; + /** + * attr: 'map' - accepts an object og key value pair + * keys: 'rdn', 'name', 'description', 'displayName', 'email', 'picture', 'memberOf' + */ + map: { [key: string]: string }; + }; + }; + }; + /** + * microsoftGraphOrg processor configuration + */ + microsoftGraphOrg?: { + /** + * attr: 'providers' - accepts object with below attributes + */ + providers: { + /** + * attr: 'target' - accepts string + * e.g. https://graph.microsoft.com/v1.0 + */ + + target: string; + /** + * attr: 'authority' - accepts string + * e.g. https://login.microsoftonline.com + */ + + authority: string; + /** + * attr: 'tenantId' - accepts string + * e.g. {"$env": "MICROSOFT_GRAPH_TENANT_ID"} + * @visibility secret + */ + + tenantId: string; + /** + * attr: 'clientId' - accepts string + * e.g. {"$env": "MICROSOFT_GRAPH_CLIENT_ID"} + * @visibility secret + */ + + clientId: string; + /** + * attr: 'clientSecret' - accepts string + * e.g. {"$env": "MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN"} + * @visibility secret + */ + + clientSecret: string; + /** + * opt-attr: 'userFilter' - accepts string + * e.g. accountEnabled eq true and userType eq 'member' + */ + + userFilter?: string; + /** + * opt-attr: 'groupFilter' - accepts string + * e.g. securityEnabled eq false and mailEnabled eq true + */ + + groupFilter?: string; + }; + }; + }; + /** + * Location specific rules used in catalog entities - accepts array of objects with below attributes + */ + locations?: Array<{ + /** + * attr: 'type' - accepts string + * e.g. url + */ + type: string; + /** + * attr: 'target' - accepts string + * e.g. https://github.com/org/repo/blob/master/users.yaml + */ + target: string; + /** + * opt-attr: 'rules' - accepts an array of objects with below attributes + */ + rules?: Array<{ + /** + * attr: 'allow' - accepts an array of string. + * e.g. [Component, API, Group, User, Template, Location] + */ + allow: Array; + /** + * opt-attr: 'locations' - accepts an array of key, value pair objects. + * keys: 'target', 'type' + * e.g.[{type: url, target: https://github.com}] + */ + locations?: Array<{ [key: string]: string }>; + }>; + }>; + }; +} diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 1a5b24f64c..dde2c2dc65 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "0.4.0", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ }, "dependencies": { "@azure/msal-node": "^1.0.0-alpha.8", - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@octokit/graphql": "^4.5.6", "@types/express": "^4.17.6", @@ -42,7 +42,7 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", - "git-url-parse": "^11.4.0", + "git-url-parse": "^11.4.3", "knex": "^0.21.6", "ldapjs": "^2.2.0", "lodash": "^4.17.15", @@ -57,7 +57,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/test-utils": "^0.1.5", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", @@ -70,6 +70,8 @@ }, "files": [ "dist", - "migrations/**/*.{js,d.ts}" - ] + "migrations/**/*.{js,d.ts}", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts index 5fa63d800a..94a08c5e73 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts @@ -39,7 +39,6 @@ describe('BuiltinKindsEntityProcessor', () => { type: 'service', owner: 'o', lifecycle: 'l', - implementsApis: ['a'], providesApis: ['b'], consumesApis: ['c'], }, @@ -47,7 +46,7 @@ describe('BuiltinKindsEntityProcessor', () => { await processor.postProcessEntity(entity, location, emit); - expect(emit).toBeCalledTimes(8); + expect(emit).toBeCalledTimes(6); expect(emit).toBeCalledWith({ type: 'relation', relation: { @@ -64,22 +63,6 @@ describe('BuiltinKindsEntityProcessor', () => { target: { kind: 'Group', namespace: 'default', name: 'o' }, }, }); - expect(emit).toBeCalledWith({ - type: 'relation', - relation: { - source: { kind: 'API', namespace: 'default', name: 'a' }, - type: 'apiProvidedBy', - target: { kind: 'Component', namespace: 'default', name: 'n' }, - }, - }); - expect(emit).toBeCalledWith({ - type: 'relation', - relation: { - source: { kind: 'Component', namespace: 'default', name: 'n' }, - type: 'providesApi', - target: { kind: 'API', namespace: 'default', name: 'a' }, - }, - }); expect(emit).toBeCalledWith({ type: 'relation', relation: { diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts index aa68222a4e..6cbec5d655 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts @@ -115,12 +115,6 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor { RELATION_OWNED_BY, RELATION_OWNER_OF, ); - doEmit( - component.spec.implementsApis, - { defaultKind: 'API', defaultNamespace: selfRef.namespace }, - RELATION_PROVIDES_API, - RELATION_API_PROVIDED_BY, - ); doEmit( component.spec.providesApis, { defaultKind: 'API', defaultNamespace: selfRef.namespace }, diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.test.ts index fdba32ef7e..19a08d219f 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.test.ts @@ -16,74 +16,9 @@ import { getVoidLogger } from '@backstage/backend-common'; import { LocationSpec } from '@backstage/catalog-model'; -import { ConfigReader } from '@backstage/config'; -import { - GithubOrgReaderProcessor, - parseUrl, - readConfig, -} from './GithubOrgReaderProcessor'; +import { GithubOrgReaderProcessor, parseUrl } from './GithubOrgReaderProcessor'; describe('GithubOrgReaderProcessor', () => { - describe('readConfig', () => { - function config( - providers: { target: string; apiBaseUrl?: string; token?: string }[], - ) { - return ConfigReader.fromConfigs([ - { - context: '', - data: { - catalog: { processors: { githubOrg: { providers } } }, - }, - }, - ]); - } - - it('adds a default GitHub entry when missing', () => { - const output = readConfig(config([])); - expect(output).toEqual([ - { - target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', - }, - ]); - }); - - it('injects the correct GitHub API base URL when missing', () => { - const output = readConfig(config([{ target: 'https://github.com' }])); - expect(output).toEqual([ - { - target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', - }, - ]); - }); - - it('rejects custom targets with no base URLs', () => { - expect(() => - readConfig(config([{ target: 'https://ghe.company.com' }])), - ).toThrow( - 'Provider at https://ghe.company.com must configure an explicit apiBaseUrl', - ); - }); - - it('rejects funky configs', () => { - expect(() => readConfig(config([{ target: 7 } as any]))).toThrow( - /target/, - ); - expect(() => readConfig(config([{ noTarget: '7' } as any]))).toThrow( - /target/, - ); - expect(() => - readConfig( - config([{ target: 'https://github.com', apiBaseUrl: 7 } as any]), - ), - ).toThrow(/apiBaseUrl/); - expect(() => - readConfig(config([{ target: 'https://github.com', token: 7 } as any])), - ).toThrow(/token/); - }); - }); - describe('parseUrl', () => { it('only supports clean org urls, and decodes them', () => { expect(() => parseUrl('https://github.com')).toThrow(); diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts index ab6e3aa008..6a83d705f6 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts @@ -18,7 +18,12 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { graphql } from '@octokit/graphql'; import { Logger } from 'winston'; -import { getOrganizationTeams, getOrganizationUsers } from './github'; +import { + getOrganizationTeams, + getOrganizationUsers, + ProviderConfig, + readGithubConfig, +} from './github'; import * as results from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; import { buildOrgHierarchy } from './util/org'; @@ -33,7 +38,7 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { static fromConfig(config: Config, options: { logger: Logger }) { return new GithubOrgReaderProcessor({ ...options, - providers: readConfig(config), + providers: readGithubConfig(config), }); } @@ -113,73 +118,6 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { * Helpers */ -/** - * The configuration parameters for a single GitHub API provider. - */ -type ProviderConfig = { - /** - * The prefix of the target that this matches on, e.g. "https://github.com", - * with no trailing slash. - */ - target: string; - - /** - * The base URL of the API of this provider, e.g. "https://api.github.com", - * with no trailing slash. - * - * May be omitted specifically for GitHub; then it will be deduced. - */ - apiBaseUrl?: string; - - /** - * The authorization token to use for requests to this provider. - * - * If no token is specified, anonymous access is used. - */ - token?: string; -}; - -// TODO(freben): Break out common code and config from here and GithubReaderProcessor -export function readConfig(config: Config): ProviderConfig[] { - const providers: ProviderConfig[] = []; - - const providerConfigs = - config.getOptionalConfigArray('catalog.processors.githubOrg.providers') ?? - []; - - // First read all the explicit providers - for (const providerConfig of providerConfigs) { - const target = providerConfig.getString('target').replace(/\/+$/, ''); - let apiBaseUrl = providerConfig.getOptionalString('apiBaseUrl'); - const token = providerConfig.getOptionalString('token'); - - if (apiBaseUrl) { - apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); - } else if (target === 'https://github.com') { - apiBaseUrl = 'https://api.github.com'; - } - - if (!apiBaseUrl) { - throw new Error( - `Provider at ${target} must configure an explicit apiBaseUrl`, - ); - } - - providers.push({ target, apiBaseUrl, token }); - } - - // If no explicit github.com provider was added, put one in the list as - // a convenience - if (!providers.some(p => p.target === 'https://github.com')) { - providers.push({ - target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', - }); - } - - return providers; -} - export function parseUrl(urlString: string): { org: string } { const path = new URL(urlString).pathname.substr(1).split('/'); diff --git a/plugins/catalog-backend/src/ingestion/processors/github/config.test.ts b/plugins/catalog-backend/src/ingestion/processors/github/config.test.ts new file mode 100644 index 0000000000..14f3caa42c --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/github/config.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { readGithubConfig } from './config'; + +describe('config', () => { + describe('readGithubConfig', () => { + function config( + providers: { target: string; apiBaseUrl?: string; token?: string }[], + ) { + return new ConfigReader({ + catalog: { processors: { githubOrg: { providers } } }, + }); + } + + it('adds a default GitHub entry when missing', () => { + const output = readGithubConfig(config([])); + expect(output).toEqual([ + { + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + }, + ]); + }); + + it('injects the correct GitHub API base URL when missing', () => { + const output = readGithubConfig( + config([{ target: 'https://github.com' }]), + ); + expect(output).toEqual([ + { + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + }, + ]); + }); + + it('rejects custom targets with no base URLs', () => { + expect(() => + readGithubConfig(config([{ target: 'https://ghe.company.com' }])), + ).toThrow( + 'Provider at https://ghe.company.com must configure an explicit apiBaseUrl', + ); + }); + + it('rejects funky configs', () => { + expect(() => readGithubConfig(config([{ target: 7 } as any]))).toThrow( + /target/, + ); + expect(() => + readGithubConfig(config([{ noTarget: '7' } as any])), + ).toThrow(/target/); + expect(() => + readGithubConfig( + config([{ target: 'https://github.com', apiBaseUrl: 7 } as any]), + ), + ).toThrow(/apiBaseUrl/); + expect(() => + readGithubConfig( + config([{ target: 'https://github.com', token: 7 } as any]), + ), + ).toThrow(/token/); + }); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/processors/github/config.ts b/plugins/catalog-backend/src/ingestion/processors/github/config.ts new file mode 100644 index 0000000000..88f2f96218 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/github/config.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; + +/** + * The configuration parameters for a single GitHub API provider. + */ +export type ProviderConfig = { + /** + * The prefix of the target that this matches on, e.g. "https://github.com", + * with no trailing slash. + */ + target: string; + + /** + * The base URL of the API of this provider, e.g. "https://api.github.com", + * with no trailing slash. + * + * May be omitted specifically for GitHub; then it will be deduced. + */ + apiBaseUrl?: string; + + /** + * The authorization token to use for requests to this provider. + * + * If no token is specified, anonymous access is used. + */ + token?: string; +}; + +// TODO(freben): Break out common code and config from here and GithubReaderProcessor +export function readGithubConfig(config: Config): ProviderConfig[] { + const providers: ProviderConfig[] = []; + + const providerConfigs = + config.getOptionalConfigArray('catalog.processors.githubOrg.providers') ?? + []; + + // First read all the explicit providers + for (const providerConfig of providerConfigs) { + const target = providerConfig.getString('target').replace(/\/+$/, ''); + let apiBaseUrl = providerConfig.getOptionalString('apiBaseUrl'); + const token = providerConfig.getOptionalString('token'); + + if (apiBaseUrl) { + apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); + } else if (target === 'https://github.com') { + apiBaseUrl = 'https://api.github.com'; + } + + if (!apiBaseUrl) { + throw new Error( + `Provider at ${target} must configure an explicit apiBaseUrl`, + ); + } + + providers.push({ target, apiBaseUrl, token }); + } + + // If no explicit github.com provider was added, put one in the list as + // a convenience + if (!providers.some(p => p.target === 'https://github.com')) { + providers.push({ + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + }); + } + + return providers; +} diff --git a/plugins/catalog-backend/src/ingestion/processors/github/index.ts b/plugins/catalog-backend/src/ingestion/processors/github/index.ts index e903ab669a..e424d7bafb 100644 --- a/plugins/catalog-backend/src/ingestion/processors/github/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/github/index.ts @@ -14,4 +14,6 @@ * limitations under the License. */ +export { readGithubConfig } from './config'; +export type { ProviderConfig } from './config'; export { getOrganizationTeams, getOrganizationUsers } from './github'; diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts b/plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts index cc43827d87..5e293766aa 100644 --- a/plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts @@ -32,9 +32,7 @@ describe('readLdapConfig', () => { }, ], }; - const actual = readLdapConfig( - ConfigReader.fromConfigs([{ context: '', data: config }]), - ); + const actual = readLdapConfig(new ConfigReader(config)); const expected = [ { target: 'target', @@ -125,9 +123,7 @@ describe('readLdapConfig', () => { }, ], }; - const actual = readLdapConfig( - ConfigReader.fromConfigs([{ context: '', data: config }]), - ); + const actual = readLdapConfig(new ConfigReader(config)); const expected = [ { target: 'target', diff --git a/plugins/catalog-backend/src/ingestion/processors/microsoftGraph/config.test.ts b/plugins/catalog-backend/src/ingestion/processors/microsoftGraph/config.test.ts index 11c63828d4..4671fd23ae 100644 --- a/plugins/catalog-backend/src/ingestion/processors/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/microsoftGraph/config.test.ts @@ -29,9 +29,7 @@ describe('readMicrosoftGraphConfig', () => { }, ], }; - const actual = readMicrosoftGraphConfig( - ConfigReader.fromConfigs([{ context: '', data: config }]), - ); + const actual = readMicrosoftGraphConfig(new ConfigReader(config)); const expected = [ { target: 'target', @@ -60,9 +58,7 @@ describe('readMicrosoftGraphConfig', () => { }, ], }; - const actual = readMicrosoftGraphConfig( - ConfigReader.fromConfigs([{ context: '', data: config }]), - ); + const actual = readMicrosoftGraphConfig(new ConfigReader(config)); const expected = [ { target: 'target', diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.test.ts b/plugins/catalog-backend/src/service/CatalogBuilder.test.ts index 58897a10a7..37337f76f1 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.test.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.test.ts @@ -47,7 +47,7 @@ describe('CatalogBuilder', () => { const env: CatalogEnvironment = { logger: getVoidLogger(), database: { getClient: async () => db }, - config: ConfigReader.fromConfigs([]), + config: new ConfigReader({}), reader, }; diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 7cef0b765a..ceee335db0 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-graphql +## 0.2.5 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 + ## 0.2.4 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index fa6bd7c4d4..fb013f53c3 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graphql", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@graphql-modules/core": "^0.7.17", "apollo-server": "^2.16.1", @@ -42,7 +42,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/test-utils": "^0.1.5", "@graphql-codegen/cli": "^1.17.7", "@graphql-codegen/typescript": "^1.17.7", diff --git a/plugins/catalog-graphql/src/graphql/module.test.ts b/plugins/catalog-graphql/src/graphql/module.test.ts index b359c4396b..e6e9d59df7 100644 --- a/plugins/catalog-graphql/src/graphql/module.test.ts +++ b/plugins/catalog-graphql/src/graphql/module.test.ts @@ -27,16 +27,11 @@ import { gql } from 'apollo-server'; describe('Catalog Module', () => { const worker = setupServer(); const mockCatalogBaseUrl = 'http://im.mock'; - const mockConfig = ConfigReader.fromConfigs([ - { - context: '', - data: { - backend: { - baseUrl: mockCatalogBaseUrl, - }, - }, + const mockConfig = new ConfigReader({ + backend: { + baseUrl: mockCatalogBaseUrl, }, - ]); + }); msw.setupDefaultHandlers(worker); diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index bc86a6ac0c..a7301e43a3 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-import +## 0.3.2 + +### Patch Changes + +- f3e75508d: Add description to Pull Request when registering a new component +- Updated dependencies [c6eeefa35] +- Updated dependencies [fb386b760] +- Updated dependencies [c911061b7] +- Updated dependencies [7c3ffc0cd] +- Updated dependencies [e7496dc3e] +- Updated dependencies [8ef71ed32] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [8dd0a906d] +- Updated dependencies [4eafdec4a] +- Updated dependencies [6b37c95bf] +- Updated dependencies [8c31c681c] +- Updated dependencies [7b98e7fee] +- Updated dependencies [178e09323] +- Updated dependencies [ac3560b42] +- Updated dependencies [0097057ed] + - @backstage/plugin-catalog-backend@0.5.0 + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/integration@0.1.4 + - @backstage/plugin-catalog@0.2.7 + ## 0.3.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 6eb744cea4..25010268f9 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,17 +30,17 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", - "@backstage/plugin-catalog-backend": "^0.4.0", - "@backstage/integration": "^0.1.3", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", + "@backstage/plugin-catalog-backend": "^0.5.0", + "@backstage/integration": "^0.1.4", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.0.6", - "git-url-parse": "^11.4.0", + "git-url-parse": "^11.4.3", "react": "^16.13.1", "react-dom": "^16.13.1", "react-hook-form": "^6.6.0", @@ -50,7 +50,7 @@ "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 4ac015ffbf..0e3ea2e1d6 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -15,7 +15,7 @@ */ import { Octokit } from '@octokit/rest'; -import { DiscoveryApi, OAuthApi } from '@backstage/core'; +import { DiscoveryApi, OAuthApi, ConfigApi } from '@backstage/core'; import { CatalogImportApi } from './CatalogImportApi'; import { AnalyzeLocationResponse } from '@backstage/plugin-catalog-backend'; import { PartialEntity } from '../util/types'; @@ -24,13 +24,16 @@ import { GitHubIntegrationConfig } from '@backstage/integration'; export class CatalogImportClient implements CatalogImportApi { private readonly discoveryApi: DiscoveryApi; private readonly githubAuthApi: OAuthApi; + private readonly configApi: ConfigApi; constructor(options: { discoveryApi: DiscoveryApi; githubAuthApi: OAuthApi; + configApi: ConfigApi; }) { this.discoveryApi = options.discoveryApi; this.githubAuthApi = options.githubAuthApi; + this.configApi = options.configApi; } async generateEntityDefinitions({ @@ -164,12 +167,23 @@ export class CatalogImportClient implements CatalogImportApi { ); }); + const appTitle = + this.configApi.getOptionalString('app.title') ?? 'Backstage'; + const appBaseUrl = this.configApi.getString('app.baseUrl'); + + const prBody = `This pull request adds a **Backstage entity metadata file** \ +to this repository so that the component can be added to the \ +[${appTitle} software catalog](${appBaseUrl}).\n\nAfter this pull request is merged, \ +the component will become available.\n\nFor more information, read an \ +[overview of the Backstage software catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview).`; + const pullRequestResponse = await octo.pulls .create({ owner, repo, title: `Add ${fileName} config file`, head: branchName, + body: prBody, base: repoData.data.default_branch, }) .catch(e => { diff --git a/plugins/catalog-import/src/plugin.ts b/plugins/catalog-import/src/plugin.ts index 3ce4918553..829be22045 100644 --- a/plugins/catalog-import/src/plugin.ts +++ b/plugins/catalog-import/src/plugin.ts @@ -20,6 +20,7 @@ import { createRouteRef, discoveryApiRef, githubAuthApiRef, + configApiRef, } from '@backstage/core'; import { catalogImportApiRef } from './api/CatalogImportApi'; import { CatalogImportClient } from './api/CatalogImportClient'; @@ -34,9 +35,13 @@ export const plugin = createPlugin({ apis: [ createApiFactory({ api: catalogImportApiRef, - deps: { discoveryApi: discoveryApiRef, githubAuthApi: githubAuthApiRef }, - factory: ({ discoveryApi, githubAuthApi }) => - new CatalogImportClient({ discoveryApi, githubAuthApi }), + deps: { + discoveryApi: discoveryApiRef, + githubAuthApi: githubAuthApiRef, + configApi: configApiRef, + }, + factory: ({ discoveryApi, githubAuthApi, configApi }) => + new CatalogImportClient({ discoveryApi, githubAuthApi, configApi }), }), ], }); diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index e47808bfa0..73f38582ff 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [dae4f3983] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/plugin-techdocs@0.5.0 + - @backstage/core@0.4.1 + - @backstage/catalog-client@0.3.4 + - @backstage/plugin-scaffolder@0.3.4 + ## 0.2.6 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index ad9cff8ed8..142ef4a1e6 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,18 +30,18 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.3.3", - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-scaffolder": "^0.3.3", - "@backstage/plugin-techdocs": "^0.4.0", + "@backstage/catalog-client": "^0.3.4", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-scaffolder": "^0.3.4", + "@backstage/plugin-techdocs": "^0.5.0", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@types/react": "^16.9", "classnames": "^2.2.6", - "git-url-parse": "^11.4.0", + "git-url-parse": "^11.4.3", "moment": "^2.26.0", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -52,7 +52,7 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@microsoft/microsoft-graph-types": "^1.25.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index dc3bf0d5ca..240ea488a7 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-circleci +## 0.2.5 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.4 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 76fc13df52..d52e5d7414 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-circleci", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -50,7 +50,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index f2a636cc4c..64e1fe2937 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-cloudbuild +## 0.2.5 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.4 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index dd040c6cea..80e7404831 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cloudbuild", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -49,7 +49,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 0524f66e69..e664883910 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-cost-insights +## 0.5.2 + +### Patch Changes + +- 48c305e69: pin all projects selection to the top of menu list +- Updated dependencies [8ef71ed32] + - @backstage/core@0.4.1 + ## 0.5.1 ### Patch Changes diff --git a/plugins/cost-insights/dev/index.tsx b/plugins/cost-insights/dev/index.tsx index fe208d5bb8..bdbb4450fa 100644 --- a/plugins/cost-insights/dev/index.tsx +++ b/plugins/cost-insights/dev/index.tsx @@ -14,20 +14,15 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { createPlugin, createApiFactory } from '@backstage/core'; import { costInsightsApiRef } from '../src/api'; import { ExampleCostInsightsClient } from '../src/client'; -import { pluginConfig } from '../src/plugin'; +import { plugin } from '../src/plugin'; -const devPlugin = createPlugin({ - ...pluginConfig, - apis: [ - createApiFactory({ - api: costInsightsApiRef, - deps: {}, - factory: () => new ExampleCostInsightsClient(), - }), - ], -}); - -createDevApp().registerPlugin(devPlugin).render(); +createDevApp() + .registerPlugin(plugin) + .registerApi({ + api: costInsightsApiRef, + deps: {}, + factory: () => new ExampleCostInsightsClient(), + }) + .render(); diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 2ff9ab7d1d..d03d698a69 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cost-insights", - "version": "0.5.1", + "version": "0.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -56,7 +56,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/cost-insights/src/plugin.ts b/plugins/cost-insights/src/plugin.ts index 58465f6711..7006d5bf5d 100644 --- a/plugins/cost-insights/src/plugin.ts +++ b/plugins/cost-insights/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createPlugin, createRouteRef, PluginConfig } from '@backstage/core'; +import { createPlugin, createRouteRef } from '@backstage/core'; import { CostInsightsPage } from './components/CostInsightsPage'; import { ProjectGrowthInstructionsPage } from './components/ProjectGrowthInstructionsPage'; import { LabelDataflowInstructionsPage } from './components/LabelDataflowInstructionsPage'; @@ -34,7 +34,7 @@ export const unlabeledDataflowAlertRef = createRouteRef({ title: 'Labeling Dataflow Jobs', }); -export const pluginConfig: PluginConfig = { +export const plugin = createPlugin({ id: 'cost-insights', register({ router, featureFlags }) { router.addRoute(rootRouteRef, CostInsightsPage); @@ -42,6 +42,4 @@ export const pluginConfig: PluginConfig = { router.addRoute(unlabeledDataflowAlertRef, LabelDataflowInstructionsPage); featureFlags.register('cost-insights-currencies'); }, -}; - -export const plugin = createPlugin(pluginConfig); +}); diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 0b4b35e0cd..4ba7d93887 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -42,7 +42,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 35852458bf..9de4a38d1d 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,7 +41,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index e9edcf76c3..d51c9bd489 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-actions +## 0.2.5 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [7dd2ef7d1] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/core-api@0.2.6 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.4 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 6c01a592d8..cfa30bfd77 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-actions", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/core-api": "^0.2.5", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/core-api": "^0.2.6", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -51,7 +51,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 4422aab210..86a7befc77 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -42,7 +42,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 367258b7f7..af30bc4b12 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -31,19 +31,19 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "graphiql": "^1.0.0-alpha.10", - "graphql": "15.3.0", + "graphql": "15.4.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/graphiql/src/index.ts b/plugins/graphiql/src/index.ts index 50698cdb4c..4b1da14079 100644 --- a/plugins/graphiql/src/index.ts +++ b/plugins/graphiql/src/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { plugin, GraphiQLPage } from './plugin'; export { GraphiQLPage as Router } from './components'; export * from './lib/api'; export * from './route-refs'; diff --git a/plugins/graphiql/src/plugin.ts b/plugins/graphiql/src/plugin.ts index 28d27802d0..a0bb79ed29 100644 --- a/plugins/graphiql/src/plugin.ts +++ b/plugins/graphiql/src/plugin.ts @@ -14,8 +14,13 @@ * limitations under the License. */ -import { createPlugin, createApiFactory } from '@backstage/core'; +import { + createPlugin, + createApiFactory, + createRoutableExtension, +} from '@backstage/core'; import { graphQlBrowseApiRef, GraphQLEndpoints } from './lib/api'; +import { graphiQLRouteRef } from './route-refs'; export const plugin = createPlugin({ id: 'graphiql', @@ -33,3 +38,10 @@ export const plugin = createPlugin({ ), ], }); + +export const GraphiQLPage = plugin.provide( + createRoutableExtension({ + component: () => import('./components').then(m => m.GraphiQLPage), + mountPoint: graphiQLRouteRef, + }), +); diff --git a/plugins/graphql/src/service/router.test.ts b/plugins/graphql/src/service/router.test.ts index 983fbbb761..3bc52b0548 100644 --- a/plugins/graphql/src/service/router.test.ts +++ b/plugins/graphql/src/service/router.test.ts @@ -22,9 +22,7 @@ import express from 'express'; describe('Router', () => { describe('/health', () => { it('should return ok', async () => { - const config = ConfigReader.fromConfigs([ - { data: { backend: { baseUrl: 'lol' } }, context: 'something' }, - ]); + const config = new ConfigReader({ backend: { baseUrl: 'lol' } }); const router = await createRouter({ config, logger: createLogger() }); const app = express().use(router); diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index c922be67b2..78792789cf 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-jenkins +## 0.3.4 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.3.3 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index f6c6466236..4c3799d550 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -46,7 +46,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index b97bc82242..9b247c174f 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 + ## 0.2.2 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 2a6f56ef33..66a36f8395 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", "@kubernetes/client-node": "^0.12.1", "@types/express": "^4.17.6", @@ -49,7 +49,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index 550703e430..339f886a53 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -20,12 +20,9 @@ import { ConfigClusterLocator } from './ConfigClusterLocator'; describe('ConfigClusterLocator', () => { it('empty clusters returns empty cluster details', async () => { - const config: Config = new ConfigReader( - { - clusters: [], - }, - 'ctx', - ); + const config: Config = new ConfigReader({ + clusters: [], + }); const sut = ConfigClusterLocator.fromConfig( config.getConfigArray('clusters'), @@ -37,18 +34,15 @@ describe('ConfigClusterLocator', () => { }); it('one clusters returns one cluster details', async () => { - const config: Config = new ConfigReader( - { - clusters: [ - { - name: 'cluster1', - url: 'http://localhost:8080', - authProvider: 'serviceAccount', - }, - ], - }, - 'ctx', - ); + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + }, + ], + }); const sut = ConfigClusterLocator.fromConfig( config.getConfigArray('clusters'), @@ -67,24 +61,21 @@ describe('ConfigClusterLocator', () => { }); it('two clusters returns two cluster details', async () => { - const config: Config = new ConfigReader( - { - clusters: [ - { - name: 'cluster1', - serviceAccountToken: 'token', - url: 'http://localhost:8080', - authProvider: 'serviceAccount', - }, - { - name: 'cluster2', - url: 'http://localhost:8081', - authProvider: 'google', - }, - ], - }, - 'ctx', - ); + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster1', + serviceAccountToken: 'token', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + }, + { + name: 'cluster2', + url: 'http://localhost:8081', + authProvider: 'google', + }, + ], + }); const sut = ConfigClusterLocator.fromConfig( config.getConfigArray('clusters'), diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts index 5677fa2d0d..63018cd338 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts @@ -60,7 +60,7 @@ describe('getCombinedClusterDetails', () => { it('throws an error when using an unsupported cluster locator', async () => { await expect( - getCombinedClusterDetails(['magic' as any], new ConfigReader({}, 'ctx')), + getCombinedClusterDetails(['magic' as any], new ConfigReader({})), ).rejects.toStrictEqual( new Error('Unsupported kubernetes.clusterLocatorMethods: "magic"'), ); diff --git a/plugins/kubernetes-backend/src/service/standaloneApplication.ts b/plugins/kubernetes-backend/src/service/standaloneApplication.ts index e23e87a7a2..50563023d0 100644 --- a/plugins/kubernetes-backend/src/service/standaloneApplication.ts +++ b/plugins/kubernetes-backend/src/service/standaloneApplication.ts @@ -36,7 +36,7 @@ export async function createStandaloneApplication( options: ApplicationOptions, ): Promise { const { enableCors, logger } = options; - const config = ConfigReader.fromConfigs([]); + const config = new ConfigReader({}); const app = express(); app.use(helmet()); diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 7ad72103a3..ef5b51cfb9 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.3.3 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-kubernetes-backend@0.2.3 + ## 0.3.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index a7b6da2ce3..649df8353f 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.3.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.0", - "@backstage/plugin-kubernetes-backend": "^0.2.2", + "@backstage/core": "^0.4.1", + "@backstage/plugin-kubernetes-backend": "^0.2.3", "@backstage/theme": "^0.2.2", "@kubernetes/client-node": "^0.12.1", "@material-ui/core": "^4.11.0", @@ -46,7 +46,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 3d1d1a491d..42035d1209 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-lighthouse +## 0.2.6 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [7dd2ef7d1] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/core-api@0.2.6 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.5 ### Patch Changes diff --git a/plugins/lighthouse/README.md b/plugins/lighthouse/README.md index 1f1d32937f..42de0a2591 100644 --- a/plugins/lighthouse/README.md +++ b/plugins/lighthouse/README.md @@ -30,24 +30,17 @@ to enable the plugin: export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse'; ``` -Then, you need to use the `lighthouseApiRef` exported from the plugin to initialize the Rest API in -your [`apis.ts`](https://github.com/backstage/backstage/blob/master/packages/app/src/apis.ts). +Modify your app routes to include the Router component exported from the plugin, for example: -```js -import { ApiHolder, ApiRegistry } from '@backstage/core'; -import { Config } from '@backstage/config'; -import { - lighthouseApiRef, - LighthouseRestApi, -} from '@backstage/plugin-lighthouse'; +```tsx +import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse'; -export const apis = (config: ConfigApi) => { - const builder = ApiRegistry.builder(); - - builder.add(lighthouseApiRef, LighthouseRestApi.fromConfig(config)); - - return builder.build() as ApiHolder; -} +// Inside App component + + // ... + } /> + // ... +; ``` Then configure the lighthouse service url in your [`app-config.yaml`](https://github.com/backstage/backstage/blob/master/app-config.yaml). @@ -86,7 +79,7 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => ( // ... } /> diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 6a5082fcab..93c4d53c21 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-lighthouse", - "version": "0.2.5", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.0", - "@backstage/core-api": "^0.2.5", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/core": "^0.4.1", + "@backstage/core-api": "^0.2.6", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -47,7 +47,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 05995acafd..2984bba457 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,7 +41,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 541c11b35b..13025d8e83 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-org +## 0.3.2 + +### Patch Changes + +- c0fac6163: Wrap entity cards on smaller screens +- ab805860a: Ensure a name is always displayed for user entities in the org plugin. This can happen when there is no profile + displayName provided (e.g. a GitHub user that has not added a name to their profile) +- 8ef71ed32: Add a `` component to `@backstage/core`. +- c5297baeb: Display the new `profile` fields (`displayName`, `email`, and `picture`) for + groups on the `GroupProfileCard`. + + This also resolves some cases where `profile` fields are missing for users or + groups and for example falls back to displaying the entity name. Adds additional test data to the ACME Corp dataset. + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.3.1 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 010fad775e..c81b44756e 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -33,7 +33,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 16a833cf56..a61dd55161 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -179,7 +179,7 @@ export const OwnershipCard = ({ {componentsWithCounters?.map(c => ( - + { const router = await createRouter({ rollbarApi, logger: getVoidLogger(), - config: ConfigReader.fromConfigs([ - { context: 'abc', data: { rollbar: { accountToken: 'foo' } } }, - ]), + config: new ConfigReader({ rollbar: { accountToken: 'foo' } }), }); app = express().use(router); }); diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 50ed3e75b1..aaa7e704d9 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-rollbar +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.6 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 7a479deba3..ff60787109 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -47,7 +47,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 2962476b72..b8585e0aec 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend +## 0.3.5 + +### Patch Changes + +- 94c65a9d4: Added configuration schema for the commonly used properties +- Updated dependencies [c911061b7] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/backend-common@0.4.1 + ## 0.3.4 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 50bddaaf41..46abade7c7 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "0.3.4", + "version": "0.3.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,9 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", + "@backstage/integration": "^0.1.4", "@gitbeaker/core": "^25.2.0", "@gitbeaker/node": "^25.2.0", "@octokit/rest": "^18.0.0", @@ -57,7 +58,7 @@ "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder-backend/sample-templates/all-templates.yaml b/plugins/scaffolder-backend/sample-templates/all-templates.yaml index 6866543ab0..e4e81fbcb3 100644 --- a/plugins/scaffolder-backend/sample-templates/all-templates.yaml +++ b/plugins/scaffolder-backend/sample-templates/all-templates.yaml @@ -4,7 +4,7 @@ metadata: name: example-templates description: A collection of all Backstage example templates spec: - type: github + type: url targets: - https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml - https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts index db3a110384..4d19069b5e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts @@ -78,7 +78,7 @@ describe('AzurePreparer', () => { }); it('calls the clone command with the correct arguments for a repository', async () => { - const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); + const preparer = new AzurePreparer(new ConfigReader({})); await preparer.prepare(mockEntity, { logger: getVoidLogger() }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, @@ -90,20 +90,15 @@ describe('AzurePreparer', () => { it('calls the clone command with the correct arguments if an access token is provided for a repository', async () => { const preparer = new AzurePreparer( - ConfigReader.fromConfigs([ - { - context: '', - data: { - scaffolder: { - azure: { - api: { - token: 'fake-token', - }, - }, + new ConfigReader({ + scaffolder: { + azure: { + api: { + token: 'fake-token', }, }, }, - ]), + }), ); await preparer.prepare(mockEntity, { logger: getVoidLogger() }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( @@ -121,7 +116,7 @@ describe('AzurePreparer', () => { }); it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { - const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); + const preparer = new AzurePreparer(new ConfigReader({})); delete mockEntity.spec.path; await preparer.prepare(mockEntity, { logger: getVoidLogger() }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( @@ -133,7 +128,7 @@ describe('AzurePreparer', () => { }); it('return the temp directory with the path to the folder if it is specified', async () => { - const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); + const preparer = new AzurePreparer(new ConfigReader({})); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { logger: getVoidLogger(), @@ -145,7 +140,7 @@ describe('AzurePreparer', () => { }); it('return the working directory with the path to the folder if it is specified', async () => { - const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); + const preparer = new AzurePreparer(new ConfigReader({})); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index a86a51e0dc..8712507026 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -42,7 +42,7 @@ const mockEntityWithProtocol = (protocol: string): TemplateEntityV1alpha1 => ({ name: 'graphql-starter', title: 'GraphQL Service', description: - 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + 'A GraphQL starter template for backstage to get you up and running\nthe best practices with GraphQL\n', uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', generation: 1, @@ -78,7 +78,7 @@ describe('GitLabPreparer', () => { ['gitlab', 'gitlab/api'].forEach(protocol => { it(`calls the clone command with the correct arguments for a repository using the ${protocol} protocol`, async () => { - const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); + const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity = mockEntityWithProtocol(protocol); await preparer.prepare(mockEntity, { logger: getVoidLogger() }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( @@ -89,22 +89,42 @@ describe('GitLabPreparer', () => { ); }); - it(`calls the clone command with the correct arguments if an access token is provided for a repository using the ${protocol} protocol`, async () => { + it(`calls the clone command with the correct arguments if an access token is provided in integrations for a repository using the ${protocol} protocol`, async () => { const preparer = new GitlabPreparer( - ConfigReader.fromConfigs([ - { - context: '', - data: { - catalog: { - processors: { - gitlabApi: { - privateToken: 'fake-token', - }, - }, + new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'fake-token', }, + ], + }, + }), + ); + mockEntity = mockEntityWithProtocol(protocol); + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + expect(mocks.Clone.clone).toHaveBeenNthCalledWith( + 1, + 'https://gitlab.com/benjdlambert/backstage-graphql-template', + expect.any(String), + { + fetchOpts: { + callbacks: { + credentials: expect.anything(), }, }, - ]), + }, + ); + }); + + it(`calls the clone command with the correct arguments if an access token is provided in scaffolder for a repository using the ${protocol} protocol`, async () => { + const preparer = new GitlabPreparer( + new ConfigReader({ + scaffolder: { + gitlab: { api: { token: 'fake-token' } }, + }, + }), ); mockEntity = mockEntityWithProtocol(protocol); await preparer.prepare(mockEntity, { logger: getVoidLogger() }); @@ -123,7 +143,7 @@ describe('GitLabPreparer', () => { }); it(`calls the clone command with the correct arguments for a repository when no path is provided using the ${protocol} protocol`, async () => { - const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); + const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity = mockEntityWithProtocol(protocol); delete mockEntity.spec.path; await preparer.prepare(mockEntity, { logger: getVoidLogger() }); @@ -136,7 +156,7 @@ describe('GitLabPreparer', () => { }); it(`return the temp directory with the path to the folder if it is specified using the ${protocol} protocol`, async () => { - const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); + const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity = mockEntityWithProtocol(protocol); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { @@ -149,7 +169,7 @@ describe('GitLabPreparer', () => { }); it('return the working directory with the path to the folder if it is specified', async () => { - const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); + const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index 605c8db2df..c2c2dcd3fd 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -13,24 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import os from 'os'; -import fs from 'fs-extra'; -import path from 'path'; -import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { parseLocationAnnotation } from '../helpers'; import { InputError } from '@backstage/backend-common'; -import { PreparerBase, PreparerOptions } from './types'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { + GitLabIntegrationConfig, + readGitLabIntegrationConfigs, +} from '@backstage/integration'; +import fs from 'fs-extra'; import GitUriParser from 'git-url-parse'; import { Clone, Cred } from 'nodegit'; -import { Config } from '@backstage/config'; +import os from 'os'; +import path from 'path'; +import { parseLocationAnnotation } from '../helpers'; +import { PreparerBase, PreparerOptions } from './types'; export class GitlabPreparer implements PreparerBase { - private readonly privateToken: string; + private readonly integrations: GitLabIntegrationConfig[]; + private readonly scaffolderToken: string | undefined; constructor(config: Config) { - this.privateToken = - config.getOptionalString('catalog.processors.gitlabApi.privateToken') ?? - ''; + this.integrations = readGitLabIntegrationConfigs( + config.getOptionalConfigArray('integrations.gitlab') ?? [], + ); + this.scaffolderToken = config.getOptionalString( + 'scaffolder.gitlab.api.token', + ); } async prepare( @@ -58,12 +66,12 @@ export class GitlabPreparer implements PreparerBase { template.spec.path ?? '.', ); - const options = this.privateToken + const token = this.getToken(parsedGitLocation.resource); + const options = token ? { fetchOpts: { callbacks: { - credentials: () => - Cred.userpassPlaintextNew('oauth2', this.privateToken), + credentials: () => Cred.userpassPlaintextNew('oauth2', token), }, }, } @@ -73,4 +81,11 @@ export class GitlabPreparer implements PreparerBase { return path.resolve(tempDir, templateDirectory); } + + private getToken(host: string): string | undefined { + return ( + this.scaffolderToken || + this.integrations.find(c => c.host === host)?.token + ); + } } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts index 226f7e3836..84be130b79 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts @@ -50,7 +50,17 @@ export class Preparers implements PreparerBuilder { if (detected) { return detected; } - throw new Error(`No preparer integration found for url "${location}"`); + if (type) { + throw new Error( + `No preparer configuration available for type '${type}' with url "${location}". ` + + "Make sure you've added appropriate configuration in the 'scaffolder' configuration section", + ); + } else { + throw new Error( + `Failed to detect preparer type. Unable to determine integration type for location "${location}". ` + + "Please add appropriate configuration to the 'integrations' configuration section", + ); + } } throw new Error(`No preparer registered for type: "${protocol}"`); } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index 961fc45cae..03a4e884ba 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -51,7 +51,17 @@ export class Publishers implements PublisherBuilder { if (detected) { return detected; } - throw new Error(`No preparer integration found for url "${location}"`); + if (type) { + throw new Error( + `No publisher configuration available for type '${type}' with url "${location}". ` + + "Make sure you've added appropriate configuration in the 'scaffolder' configuration section", + ); + } else { + throw new Error( + `Failed to detect publisher type. Unable to determine integration type for location "${location}". ` + + "Please add appropriate configuration to the 'integrations' configuration section", + ); + } } throw new Error(`No publisher registered for type: "${protocol}"`); } diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 633d16b2a4..4d610299eb 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -55,11 +55,8 @@ describe('createRouter - working directory', () => { }); const workDirConfig = (path: string) => ({ - context: '', - data: { - backend: { - workingDirectory: path, - }, + backend: { + workingDirectory: path, }, }); @@ -91,7 +88,7 @@ describe('createRouter - working directory', () => { preparers: new Preparers(), templaters: new Templaters(), publishers: new Publishers(), - config: ConfigReader.fromConfigs([workDirConfig('/path')]), + config: new ConfigReader(workDirConfig('/path')), dockerClient: new Docker(), entityClient: mockedEntityClient, }), @@ -104,7 +101,7 @@ describe('createRouter - working directory', () => { preparers: mockPreparers, templaters: new Templaters(), publishers: new Publishers(), - config: ConfigReader.fromConfigs([workDirConfig('/path')]), + config: new ConfigReader(workDirConfig('/path')), dockerClient: new Docker(), entityClient: mockedEntityClient, }); @@ -127,7 +124,7 @@ describe('createRouter - working directory', () => { preparers: mockPreparers, templaters: new Templaters(), publishers: new Publishers(), - config: ConfigReader.fromConfigs([]), + config: new ConfigReader({}), dockerClient: new Docker(), entityClient: mockedEntityClient, }); @@ -190,7 +187,7 @@ describe('createRouter', () => { preparers: new Preparers(), templaters: new Templaters(), publishers: new Publishers(), - config: ConfigReader.fromConfigs([]), + config: new ConfigReader({}), dockerClient: new Docker(), entityClient: generateEntityClient(template), }); diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 08915241e0..f7d68369ae 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder +## 0.3.4 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.3.3 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 6c802d8130..6b3c64c26d 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -50,7 +50,7 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index f00437b19a..f85c13b47c 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search +## 0.2.4 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + - @backstage/plugin-catalog@0.2.7 + ## 0.2.3 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index ffafbafbbd..a66a9ba323 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", - "@backstage/plugin-catalog": "^0.2.6", - "@backstage/catalog-model": "^0.5.0", + "@backstage/core": "^0.4.1", + "@backstage/plugin-catalog": "^0.2.7", + "@backstage/catalog-model": "^0.6.0", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -43,7 +43,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 862dfd30eb..f5b5f5efd8 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-sentry +## 0.3.1 + +### Patch Changes + +- 962d1ad66: Added configuration schema for the commonly used properties +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + ## 0.3.0 ### Minor Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 7b4ca9f083..404ff90f34 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -45,7 +45,7 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index bccff558c8..62f9d857a7 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sonarqube +## 0.1.7 + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/core@0.4.1 + ## 0.1.6 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 7d9467b42b..c5d6433871 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube", - "version": "0.1.6", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,8 +32,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -46,7 +46,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index f10eef259d..471f195381 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -44,7 +44,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 92901f7e42..9d57ebc481 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-techdocs-backend +## 0.4.0 + +### Minor Changes + +- dae4f3983: _Breaking changes_ + + 1. Added option to use Google Cloud Storage as a choice to store the static generated files for TechDocs. + It can be configured using `techdocs.publisher.type` option in `app-config.yaml`. + Step-by-step guide to configure GCS is available here https://backstage.io/docs/features/techdocs/using-cloud-storage + Set `techdocs.publisher.type` to `'local'` if you want to continue using local filesystem to store TechDocs files. + + 2. `techdocs.builder` is now required and can be set to `'local'` or `'external'`. (Set it to `'local'` for now, since CI/CD build + workflow for TechDocs will be available soon (in few weeks)). + If builder is set to 'local' and you open a TechDocs page, `techdocs-backend` will try to generate the docs, publish to storage and + show the generated docs afterwords. + If builder is set to `'external'`, `techdocs-backend` will only fetch the docs and will NOT try to generate and publish. In this case of `'external'`, + we assume that docs are being built in the CI/CD pipeline of the repository. + TechDocs will not assume a default value for `techdocs.builder`. It is better to explicitly define it in the `app-config.yaml`. + + 3. When configuring TechDocs in your backend, there is a difference in how a new publisher is created. + + ``` + --- const publisher = new LocalPublish(logger, discovery); + +++ const publisher = Publisher.fromConfig(config, logger, discovery); + ``` + + Based on the config `techdocs.publisher.type`, the publisher could be either Local publisher or Google Cloud Storage publisher. + + 4. `techdocs.storageUrl` is now a required config. Should be `http://localhost:7000/api/techdocs/static/docs` in most setups. + + 5. Parts of `@backstage/plugin-techdocs-backend` have been moved to a new package `@backstage/techdocs-common` to generate docs. Also to publish docs + to-and-fro between TechDocs and a storage (either local or external). However, a Backstage app does NOT need to import the `techdocs-common` package - + app should only import `@backstage/plugin-techdocs` and `@backstage/plugin-techdocs-backend`. + + _Patch changes_ + + 1. See all of TechDocs config options and its documentation https://backstage.io/docs/features/techdocs/configuration + + 2. Logic about serving static files and metadata retrieval have been abstracted away from the router in `techdocs-backend` to the instance of publisher. + + 3. Removed Material UI Spinner from TechDocs header. Spinners cause unnecessary UX distraction. + Case 1 (when docs are built and are to be served): Spinners appear for a split second before the name of site shows up. This unnecessarily distracts eyes because spinners increase the size of the Header. A dot (.) would do fine. Definitely more can be done. + Case 2 (when docs are being generated): There is already a linear progress bar (which is recommended in Storybook). + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [dae4f3983] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [4eafdec4a] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/techdocs-common@0.2.0 + - @backstage/backend-common@0.4.1 + ## 0.3.2 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index fc11122ead..5552d87f3f 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.3.2", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.4.0", - "@backstage/catalog-model": "^0.5.0", + "@backstage/backend-common": "^0.4.1", + "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/techdocs-common": "^0.1.1", + "@backstage/techdocs-common": "^0.2.0", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", @@ -44,7 +44,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/techdocs-backend/src/service/standaloneServer.ts b/plugins/techdocs-backend/src/service/standaloneServer.ts index c1c4dba8d1..3faf736ca0 100644 --- a/plugins/techdocs-backend/src/service/standaloneServer.ts +++ b/plugins/techdocs-backend/src/service/standaloneServer.ts @@ -41,18 +41,13 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'techdocs-backend' }); - const config = ConfigReader.fromConfigs([ - { - context: '', - data: { - techdocs: { - publisher: { - type: 'local', - }, - }, + const config = new ConfigReader({ + techdocs: { + publisher: { + type: 'local', }, }, - ]); + }); const discovery = SingleHostDiscovery.fromConfig(config); logger.debug('Creating application...'); diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 26ee57fb86..d7bb8506b2 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/plugin-techdocs +## 0.5.0 + +### Minor Changes + +- dae4f3983: _Breaking changes_ + + 1. Added option to use Google Cloud Storage as a choice to store the static generated files for TechDocs. + It can be configured using `techdocs.publisher.type` option in `app-config.yaml`. + Step-by-step guide to configure GCS is available here https://backstage.io/docs/features/techdocs/using-cloud-storage + Set `techdocs.publisher.type` to `'local'` if you want to continue using local filesystem to store TechDocs files. + + 2. `techdocs.builder` is now required and can be set to `'local'` or `'external'`. (Set it to `'local'` for now, since CI/CD build + workflow for TechDocs will be available soon (in few weeks)). + If builder is set to 'local' and you open a TechDocs page, `techdocs-backend` will try to generate the docs, publish to storage and + show the generated docs afterwords. + If builder is set to `'external'`, `techdocs-backend` will only fetch the docs and will NOT try to generate and publish. In this case of `'external'`, + we assume that docs are being built in the CI/CD pipeline of the repository. + TechDocs will not assume a default value for `techdocs.builder`. It is better to explicitly define it in the `app-config.yaml`. + + 3. When configuring TechDocs in your backend, there is a difference in how a new publisher is created. + + ``` + --- const publisher = new LocalPublish(logger, discovery); + +++ const publisher = Publisher.fromConfig(config, logger, discovery); + ``` + + Based on the config `techdocs.publisher.type`, the publisher could be either Local publisher or Google Cloud Storage publisher. + + 4. `techdocs.storageUrl` is now a required config. Should be `http://localhost:7000/api/techdocs/static/docs` in most setups. + + 5. Parts of `@backstage/plugin-techdocs-backend` have been moved to a new package `@backstage/techdocs-common` to generate docs. Also to publish docs + to-and-fro between TechDocs and a storage (either local or external). However, a Backstage app does NOT need to import the `techdocs-common` package - + app should only import `@backstage/plugin-techdocs` and `@backstage/plugin-techdocs-backend`. + + _Patch changes_ + + 1. See all of TechDocs config options and its documentation https://backstage.io/docs/features/techdocs/configuration + + 2. Logic about serving static files and metadata retrieval have been abstracted away from the router in `techdocs-backend` to the instance of publisher. + + 3. Removed Material UI Spinner from TechDocs header. Spinners cause unnecessary UX distraction. + Case 1 (when docs are built and are to be served): Spinners appear for a split second before the name of site shows up. This unnecessarily distracts eyes because spinners increase the size of the Header. A dot (.) would do fine. Definitely more can be done. + Case 2 (when docs are being generated): There is already a linear progress bar (which is recommended in Storybook). + +### Patch Changes + +- Updated dependencies [c911061b7] +- Updated dependencies [dae4f3983] +- Updated dependencies [8ef71ed32] +- Updated dependencies [0e6298f7e] +- Updated dependencies [7dd2ef7d1] +- Updated dependencies [ac3560b42] + - @backstage/catalog-model@0.6.0 + - @backstage/techdocs-common@0.2.0 + - @backstage/core@0.4.1 + - @backstage/core-api@0.2.6 + - @backstage/plugin-catalog@0.2.7 + ## 0.4.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 15325ed7bc..361825e71a 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.4.0", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,13 +31,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.5.0", - "@backstage/core": "^0.4.0", - "@backstage/core-api": "^0.2.5", - "@backstage/plugin-catalog": "^0.2.6", + "@backstage/catalog-model": "^0.6.0", + "@backstage/core": "^0.4.1", + "@backstage/core-api": "^0.2.6", + "@backstage/plugin-catalog": "^0.2.7", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", - "@backstage/techdocs-common": "^0.1.1", + "@backstage/techdocs-common": "^0.2.0", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -50,7 +50,7 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 57aff26d27..fed2b4d3f7 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,7 +41,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/user-settings/src/components/AuthProviders/AuthProviders.test.tsx b/plugins/user-settings/src/components/AuthProviders/AuthProviders.test.tsx index 4399b6bd3e..072c90ddac 100644 --- a/plugins/user-settings/src/components/AuthProviders/AuthProviders.test.tsx +++ b/plugins/user-settings/src/components/AuthProviders/AuthProviders.test.tsx @@ -37,18 +37,13 @@ const mockGoogleAuth = { }; const createConfig = () => - ConfigReader.fromConfigs([ - { - context: '', - data: { - auth: { - providers: { - google: { development: {} }, - }, - }, + new ConfigReader({ + auth: { + providers: { + google: { development: {} }, }, }, - ]); + }); const config = createConfig(); diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index d61935ef6e..b8658ea2f8 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.0", + "@backstage/core": "^0.4.1", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,7 +41,7 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.1", + "@backstage/cli": "^0.4.2", "@backstage/dev-utils": "^0.1.6", "@backstage/test-utils": "^0.1.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/yarn.lock b/yarn.lock index 65bb891a59..afc2047087 100644 --- a/yarn.lock +++ b/yarn.lock @@ -196,6 +196,13 @@ dependencies: "@babel/types" "^7.10.4" +"@babel/helper-annotate-as-pure@^7.12.10": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d" + integrity sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ== + dependencies: + "@babel/types" "^7.12.10" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" @@ -213,6 +220,15 @@ "@babel/helper-module-imports" "^7.10.4" "@babel/types" "^7.10.5" +"@babel/helper-builder-react-jsx-experimental@^7.12.10": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.10.tgz#a58cb96a793dc0fcd5c9ed3bb36d62fdc60534c2" + integrity sha512-3Kcr2LGpL7CTRDTTYm1bzeor9qZbxbvU2AxsLA6mUG9gYarSfIKMK0UlU+azLWI+s0+BH768bwyaziWB2NOJlQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.10" + "@babel/helper-module-imports" "^7.12.5" + "@babel/types" "^7.12.10" + "@babel/helper-builder-react-jsx-experimental@^7.12.4": version "7.12.4" resolved "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.4.tgz#55fc1ead5242caa0ca2875dcb8eed6d311e50f48" @@ -240,7 +256,7 @@ browserslist "^4.14.5" semver "^5.5.0" -"@babel/helper-create-class-features-plugin@^7.10.4", "@babel/helper-create-class-features-plugin@^7.10.5": +"@babel/helper-create-class-features-plugin@^7.10.4": version "7.10.5" resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== @@ -532,7 +548,7 @@ "@babel/helper-remap-async-to-generator" "^7.12.1" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.8.3": +"@babel/plugin-proposal-class-properties@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== @@ -548,14 +564,14 @@ "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-decorators@^7.8.3": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4" - integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ== +"@babel/plugin-proposal-decorators@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.1.tgz#59271439fed4145456c41067450543aee332d15f" + integrity sha512-knNIuusychgYN8fGJHONL0RbFxLGawhXOJNLBk75TniTsZZeA+wdkDuv6wp4lGwzQEKjZi6/WYtnb3udNPmQmQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-decorators" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.12.1" "@babel/plugin-proposal-dynamic-import@^7.12.1": version "7.12.1" @@ -565,13 +581,13 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-export-default-from@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.10.4.tgz#08f66eef0067cbf6a7bc036977dcdccecaf0c6c5" - integrity sha512-G1l00VvDZ7Yk2yRlC5D8Ybvu3gmeHS3rCHoUYdjrqGYUtdeOBoRypnvDZ5KQqxyaiiGHWnVDeSEzA5F9ozItig== +"@babel/plugin-proposal-export-default-from@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.1.tgz#c6e62d668a8abcfe0d28b82f560395fecb611c5a" + integrity sha512-z5Q4Ke7j0AexQRfgUvnD+BdCSgpTEKnqQ3kskk2jWtOBulxICzd1X9BGt7kmWftxZ2W3++OZdt5gtmC8KLxdRQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-export-default-from" "^7.10.4" + "@babel/plugin-syntax-export-default-from" "^7.12.1" "@babel/plugin-proposal-export-namespace-from@^7.12.1": version "7.12.1" @@ -597,14 +613,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" - integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": version "7.12.1" resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" @@ -621,7 +629,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.9.6": +"@babel/plugin-proposal-object-rest-spread@^7.0.0": version "7.11.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== @@ -647,16 +655,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.10.1": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" - integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-proposal-optional-chaining@^7.12.7": +"@babel/plugin-proposal-optional-chaining@^7.12.1", "@babel/plugin-proposal-optional-chaining@^7.12.7": version "7.12.7" resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz#e02f0ea1b5dc59d401ec16fb824679f683d3303c" integrity sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA== @@ -673,14 +672,6 @@ "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-private-methods@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" - integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-proposal-unicode-property-regex@^7.12.1": version "7.12.1" resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz#2a183958d417765b9eae334f47758e5d6a82e072" @@ -725,10 +716,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-decorators@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c" - integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw== +"@babel/plugin-syntax-decorators@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.1.tgz#81a8b535b284476c41be6de06853a8802b98c5dd" + integrity sha512-ir9YW5daRrTYiy9UJ2TzdNIJEZu8KclVzDcfSt4iEmOtwQ4llPtWInNKJyKnVXp1vE4bbVd5S31M/im3mYMO1w== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -739,10 +730,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.10.4.tgz#e5494f95006355c10292a0ff1ce42a5746002ec8" - integrity sha512-79V6r6Pgudz0RnuMGp5xidu6Z+bPFugh8/Q9eDHonmLp4wKFAZDwygJwYgCzuDu8lFA/sYyT+mc5y2wkd7bTXA== +"@babel/plugin-syntax-export-default-from@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.1.tgz#a9eb31881f4f9a1115a3d2c6d64ac3f6016b5a9d" + integrity sha512-dP5eGg6tHEkhnRD2/vRG/KJKRSg8gtxu2i+P/8/yFPJn/CfPU5G0/7Gks2i3M6IOVAPQekmsLN9LPsmXFFL4Uw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -760,12 +751,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-flow@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" - integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== +"@babel/plugin-syntax-flow@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz#a77670d9abe6d63e8acadf4c31bb1eb5a506bbdd" + integrity sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" @@ -851,14 +842,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-typescript@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz#2f55e770d3501e83af217d782cb7517d7bb34d25" - integrity sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ== +"@babel/plugin-syntax-typescript@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.1.tgz#460ba9d77077653803c3dd2e673f76d66b4029e5" + integrity sha512-UZNEcCY+4Dp9yYRCAHrHDU+9ZXLYaY9MgBXSRLkB9WjYFRR6quJBumfVrEkUxrePPBwFcpWfNKXqVRQQtm7mMA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.8.3": +"@babel/plugin-transform-arrow-functions@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== @@ -895,7 +886,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.8.3": +"@babel/plugin-transform-block-scoping@^7.0.0": version "7.11.1" resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== @@ -909,7 +900,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.9.5": +"@babel/plugin-transform-classes@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== @@ -951,7 +942,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.9.5": +"@babel/plugin-transform-destructuring@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== @@ -1004,15 +995,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-flow" "^7.10.4" -"@babel/plugin-transform-flow-strip-types@^7.9.0": - version "7.9.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" - integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== +"@babel/plugin-transform-flow-strip-types@^7.12.1": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.10.tgz#d85e30ecfa68093825773b7b857e5085bbd32c95" + integrity sha512-0ti12wLTLeUIzu9U7kjqIn4MyOL7+Wibc7avsHhj4o1l5C0ATs8p2IMHrVYjm9t9wzhfEO6S3kxax0Rpdo8LTg== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-flow" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.12.1" -"@babel/plugin-transform-for-of@^7.0.0", "@babel/plugin-transform-for-of@^7.9.0": +"@babel/plugin-transform-for-of@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== @@ -1148,7 +1139,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.12.1" -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.10.4", "@babel/plugin-transform-parameters@^7.9.5": +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.10.4": version "7.10.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== @@ -1231,6 +1222,16 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" +"@babel/plugin-transform-react-jsx@^7.12.10": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.10.tgz#a7af3097c73479123594c8c8fe39545abebd44e3" + integrity sha512-MM7/BC8QdHXM7Qc1wdnuk73R4gbuOpfrSUgfV/nODGc86sPY1tgmY2M9E9uAnf2e4DOIp8aKGWqgZfQxnTNGuw== + dependencies: + "@babel/helper-builder-react-jsx" "^7.10.4" + "@babel/helper-builder-react-jsx-experimental" "^7.12.10" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.12.1" + "@babel/plugin-transform-react-jsx@^7.12.7": version "7.12.7" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.7.tgz#8b14d45f6eccd41b7f924bcb65c021e9f0a06f7f" @@ -1263,7 +1264,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.8.3": +"@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== @@ -1277,7 +1278,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.8.3": +"@babel/plugin-transform-spread@^7.0.0": version "7.11.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== @@ -1300,7 +1301,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.8.3": +"@babel/plugin-transform-template-literals@^7.0.0": version "7.10.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== @@ -1322,14 +1323,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-typescript@^7.10.4": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz#2b4879676af37342ebb278216dd090ac67f13abb" - integrity sha512-edJsNzTtvb3MaXQwj8403B7mZoGu9ElDJQZOKjGUnvilquxBA3IQoEIOvkX/1O8xfAsnHS/oQhe2w/IXrr+w0w== +"@babel/plugin-transform-typescript@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz#d92cc0af504d510e26a754a7dbc2e5c8cd9c7ab4" + integrity sha512-VrsBByqAIntM+EYMqSm59SiMEf7qkmI9dqMt6RbD/wlwueWmYcI0FFK5Fj47pP6DRZm+3teXjosKlwcZJ5lIMw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-create-class-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-typescript" "^7.10.4" + "@babel/plugin-syntax-typescript" "^7.12.1" "@babel/plugin-transform-unicode-escapes@^7.12.1": version "7.12.1" @@ -1346,7 +1347,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.9.5", "@babel/preset-env@^7.9.6": +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.9.5": version "7.12.7" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz#54ea21dbe92caf6f10cb1a0a576adc4ebf094b55" integrity sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew== @@ -1418,13 +1419,13 @@ core-js-compat "^3.7.0" semver "^5.5.0" -"@babel/preset-flow@^7.0.0": - version "7.9.0" - resolved "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.9.0.tgz#fee847c3e090b0b2d9227c1949e4da1d1379280d" - integrity sha512-88uSmlshIrlmPkNkEcx3UpSZ6b8n0UGBq0/0ZMZCF/uxAW0XIAUuDHBhIOAh0pvweafH4RxOwi/H3rWhtqOYPA== +"@babel/preset-flow@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.12.1.tgz#1a81d376c5a9549e75352a3888f8c273455ae940" + integrity sha512-UAoyMdioAhM6H99qPoKvpHMzxmNVXno8GYU/7vZmGaHk6/KqfDYL1W0NxszVbJ2EP271b7e6Ox+Vk2A9QsB3Sw== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-flow-strip-types" "^7.9.0" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-flow-strip-types" "^7.12.1" "@babel/preset-modules@^0.1.3": version "0.1.3" @@ -1437,7 +1438,18 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.12.5", "@babel/preset-react@^7.8.3", "@babel/preset-react@^7.9.4": +"@babel/preset-react@^7.12.1": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.10.tgz#4fed65f296cbb0f5fb09de6be8cddc85cc909be9" + integrity sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.12.1" + "@babel/plugin-transform-react-jsx" "^7.12.10" + "@babel/plugin-transform-react-jsx-development" "^7.12.7" + "@babel/plugin-transform-react-pure-annotations" "^7.12.1" + +"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.9.4": version "7.12.7" resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.7.tgz#36d61d83223b07b6ac4ec55cf016abb0f70be83b" integrity sha512-wKeTdnGUP5AEYCYQIMeXMMwU7j+2opxrG0WzuZfxuuW9nhKvvALBjl67653CWamZJVefuJGI219G591RSldrqQ== @@ -1450,18 +1462,19 @@ "@babel/plugin-transform-react-jsx-source" "^7.12.1" "@babel/plugin-transform-react-pure-annotations" "^7.12.1" -"@babel/preset-typescript@^7.9.0": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz#7d5d052e52a682480d6e2cc5aa31be61c8c25e36" - integrity sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ== +"@babel/preset-typescript@^7.12.1": + version "7.12.7" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.12.7.tgz#fc7df8199d6aae747896f1e6c61fc872056632a3" + integrity sha512-nOoIqIqBmHBSEgBXWR4Dv/XBehtIFcw9PqZw6rFYuKrzsZmOQm3PR5siLBnKZFEsDb03IegG8nSjU/iXXXYRmw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-transform-typescript" "^7.10.4" + "@babel/helper-validator-option" "^7.12.1" + "@babel/plugin-transform-typescript" "^7.12.1" -"@babel/register@^7.10.5": - version "7.11.5" - resolved "https://registry.npmjs.org/@babel/register/-/register-7.11.5.tgz#79becf89e0ddd0fba8b92bc279bc0f5d2d7ce2ea" - integrity sha512-CAml0ioKX+kOAvBQDHa/+t1fgOt3qkTIz0TrRtRAT6XY0m5qYZXR85k6/sLCNPMGhYDlCFHCYuU0ybTJbvlC6w== +"@babel/register@^7.12.1": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/register/-/register-7.12.10.tgz#19b87143f17128af4dbe7af54c735663b3999f60" + integrity sha512-EvX/BvMMJRAA3jZgILWgbsrHwBQvllC5T8B29McyME8DvkdOxk4ujESfrMvME8IHSDvWXrmMXxPvA/lx2gqPLQ== dependencies: find-cache-dir "^2.0.0" lodash "^4.17.19" @@ -1485,7 +1498,7 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.12.5" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== @@ -1621,8 +1634,17 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@babel/types@^7.12.10": + version "7.12.10" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz#7965e4a7260b26f09c56bcfcb0498af1f6d9b260" + integrity sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@backstage/catalog-model@^0.2.0": - version "0.5.0" + version "0.6.0" dependencies: "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" @@ -1633,7 +1655,7 @@ yup "^0.29.3" "@backstage/catalog-model@^0.3.0": - version "0.5.0" + version "0.6.0" dependencies: "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" @@ -1644,10 +1666,10 @@ yup "^0.29.3" "@backstage/core@^0.3.0": - version "0.4.0" + version "0.4.1" dependencies: "@backstage/config" "^0.1.2" - "@backstage/core-api" "^0.2.5" + "@backstage/core-api" "^0.2.6" "@backstage/theme" "^0.2.2" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" @@ -1953,7 +1975,7 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" -"@emotion/core@^10.0.0", "@emotion/core@^10.0.20", "@emotion/core@^10.0.28": +"@emotion/core@^10.0.0", "@emotion/core@^10.0.28": version "10.0.28" resolved "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz#bb65af7262a234593a9e952c041d0f1c9b9bef3d" integrity sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA== @@ -1965,6 +1987,18 @@ "@emotion/sheet" "0.9.4" "@emotion/utils" "0.11.3" +"@emotion/core@^10.1.1": + version "10.1.1" + resolved "https://registry.npmjs.org/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" + integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA== + dependencies: + "@babel/runtime" "^7.5.5" + "@emotion/cache" "^10.0.27" + "@emotion/css" "^10.0.27" + "@emotion/serialize" "^0.11.15" + "@emotion/sheet" "0.9.4" + "@emotion/utils" "0.11.3" + "@emotion/css@^10.0.27": version "10.0.27" resolved "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" @@ -2017,7 +2051,7 @@ "@emotion/serialize" "^0.11.15" "@emotion/utils" "0.11.3" -"@emotion/styled@^10.0.0", "@emotion/styled@^10.0.17": +"@emotion/styled@^10.0.0", "@emotion/styled@^10.0.23": version "10.0.27" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf" integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q== @@ -3886,6 +3920,11 @@ "@octokit/types" "^5.0.0" universal-user-agent "^6.0.0" +"@octokit/openapi-types@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.0.0.tgz#6d8f8ad9db3b75a39115f5def2654df8bed39f28" + integrity sha512-J4bfM7lf8oZvEAdpS71oTvC1ofKxfEZgU5vKVwzZKi4QPiL82udjpseJwxPid9Pu2FNmyRQOX4iEj6W1iOSnPw== + "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" @@ -4054,6 +4093,23 @@ resolved "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6" integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw== +"@pmmmwh/react-refresh-webpack-plugin@^0.4.2": + version "0.4.3" + resolved "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" + integrity sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ== + dependencies: + ansi-html "^0.0.7" + error-stack-parser "^2.0.6" + html-entities "^1.2.1" + native-url "^0.2.6" + schema-utils "^2.6.5" + source-map "^0.7.3" + +"@popperjs/core@^2.5.4": + version "2.5.4" + resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.5.4.tgz#de25b5da9f727985a3757fd59b5d028aba75841a" + integrity sha512-ZpKr+WTb8zsajqgDkvCEWgp6d5eJT6Q63Ng2neTbzBO76Lbe91vX/iVIW9dikq+Fs3yEo+ls4cxeXABD2LtcbQ== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -4343,270 +4399,175 @@ resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-9.0.0.tgz#be68cfaf212599f0bfeb6536c7c58ec05d2b6fba" integrity sha512-ZsXTwMA68ZCz943U4N8XwprdWcc7ErOO/IW8PewLK5lycCZtLnmRkOvAbae7O5qNJPD8b/l0iUMTLaZuwjXWwg== -"@spotify/prettier-config@^8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-8.0.0.tgz#8b6c2bd579ddc54887155a0721fe04e96c89f7f2" - integrity sha512-so8w32ZV42CHWxOEXcBtbNO/hLXFrQNXVmhfzhUI6dVB9cq2xjRaiqu8GjFj8LvKbWpPj+S+KwTIS4aDVWqrFQ== +"@spotify/prettier-config@^9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-9.0.0.tgz#7b562d56573c6fc0094446fbc92b22bc318945dc" + integrity sha512-In1q0tIiqTYKAGe3KOHDcFDdZRFISyQeSeipeTHGfki23ebHRZcjxvqj5SSdBkw65D4VpSREMi0s9i5iJiMcTw== -"@storybook/addon-actions@^6.0.21": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.0.26.tgz#d0de9e4d78a8f8f5bf8730c04d0b6d1741c29273" - integrity sha512-9tWbAqSwzWWVz8zwAndZFusZYjIcRYgZUC0LqC8QlH79DgF3ASjw9y97+w1VTTAzdb6LYnsMuSpX6+8m5hrR4g== +"@storybook/addon-actions@^6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.1.11.tgz#73e91cc95c45ea477cfd4f3603f6b95f5829eab6" + integrity sha512-J44XLx2G732OG7Az79Cpk5UlI5SyXHeQqdykwT/4IEQXSBXAYWSTIJJjpJdcjR/D+zpklab1QDSiWxCrKbe81A== dependencies: - "@storybook/addons" "6.0.26" - "@storybook/api" "6.0.26" - "@storybook/client-api" "6.0.26" - "@storybook/components" "6.0.26" - "@storybook/core-events" "6.0.26" - "@storybook/theming" "6.0.26" + "@storybook/addons" "6.1.11" + "@storybook/api" "6.1.11" + "@storybook/client-api" "6.1.11" + "@storybook/components" "6.1.11" + "@storybook/core-events" "6.1.11" + "@storybook/theming" "6.1.11" core-js "^3.0.1" fast-deep-equal "^3.1.1" global "^4.3.2" lodash "^4.17.15" polished "^3.4.4" prop-types "^15.7.2" - react "^16.8.3" react-inspector "^5.0.1" - regenerator-runtime "^0.13.3" - ts-dedent "^1.1.1" + regenerator-runtime "^0.13.7" + ts-dedent "^2.0.0" util-deprecate "^1.0.2" uuid "^8.0.0" -"@storybook/addon-links@^6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.0.21.tgz#6d4497933d560615617eaffeacec00ad8a788b01" - integrity sha512-5cRFxXS9BviDbS+DCKElr1vSafDcRhX74iIAWl/yOBUldUZvR+gX3WOZ7bO+OBSlQ1NJkt1NUAMag3aiJa4UUw== +"@storybook/addon-links@^6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.1.11.tgz#84b20b0c13bbfc8270cdf52389ce52f98c415b6a" + integrity sha512-OIBeOdTHNr/egIuyOUEtEBtZJXVp9PEPQ4MDxvKsCgpnXruPhjenPNW+mQKxm4SefpePW7zkx6k1ubpYVJUeag== dependencies: - "@storybook/addons" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/core-events" "6.0.21" + "@storybook/addons" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/core-events" "6.1.11" "@storybook/csf" "0.0.1" - "@storybook/router" "6.0.21" + "@storybook/router" "6.1.11" "@types/qs" "^6.9.0" core-js "^3.0.1" global "^4.3.2" prop-types "^15.7.2" qs "^6.6.0" - regenerator-runtime "^0.13.3" - ts-dedent "^1.1.1" + regenerator-runtime "^0.13.7" + ts-dedent "^2.0.0" -"@storybook/addon-storysource@^6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.0.21.tgz#fce9a6de8b276239dbb49b809f3b5efd9fbcecb4" - integrity sha512-h8bu2twPfBRbWlxg8LRtCM5/r2FxWahJa0RC70qDX6eNdzDw6Xv0B8bZsVxKPWqBNQbwYPz5ui44ym53dFDM/Q== +"@storybook/addon-storysource@^6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.1.11.tgz#f5413a51262f62eed3b399c4d9861b873f2c2827" + integrity sha512-uscKgALJa/inMFPb/Fpe9LXB6c6WlrGOfaUiAdrahn9gZbDAG9qunaSkAZ9EPWckSosq3RuV59HMCQ2Bolh/lQ== dependencies: - "@storybook/addons" "6.0.21" - "@storybook/api" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/components" "6.0.21" - "@storybook/router" "6.0.21" - "@storybook/source-loader" "6.0.21" - "@storybook/theming" "6.0.21" + "@storybook/addons" "6.1.11" + "@storybook/api" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/components" "6.1.11" + "@storybook/router" "6.1.11" + "@storybook/source-loader" "6.1.11" + "@storybook/theming" "6.1.11" core-js "^3.0.1" estraverse "^4.2.0" loader-utils "^2.0.0" prettier "~2.0.5" prop-types "^15.7.2" - react "^16.9.17" - react-syntax-highlighter "^12.2.1" - regenerator-runtime "^0.13.3" + react-syntax-highlighter "^13.5.0" + regenerator-runtime "^0.13.7" -"@storybook/addons@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.0.21.tgz#bd5229652102c3aed59b78ef6920ff6b482b4d78" - integrity sha512-yDttNLc3vXqBxwK795ykgzTC6MpvuXDQuF4LHSlHZQe6wsMu1m3fljnbYdafJWdx6cNZwUblU3KYcR11PqhkPg== +"@storybook/addons@6.1.11", "@storybook/addons@^6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.1.11.tgz#cb4578411ca00ccb206b484df5a171ccaca34719" + integrity sha512-OZXsdmn60dVe482l9zWxzOqqJApD2jggk/8QJKn3/Ub9posmqdqg712bW6v71BBe0UXXG/QfkZA7gcyiyEENbw== dependencies: - "@storybook/api" "6.0.21" - "@storybook/channels" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/core-events" "6.0.21" - "@storybook/router" "6.0.21" - "@storybook/theming" "6.0.21" + "@storybook/api" "6.1.11" + "@storybook/channels" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/core-events" "6.1.11" + "@storybook/router" "6.1.11" + "@storybook/theming" "6.1.11" core-js "^3.0.1" global "^4.3.2" - regenerator-runtime "^0.13.3" + regenerator-runtime "^0.13.7" -"@storybook/addons@6.0.26", "@storybook/addons@^6.0.21": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.0.26.tgz#343cbea3eee2d39413b80bc2d66535a7f61488fc" - integrity sha512-OhAApFKgsj9an7FLYfHI4cJQuZ4Zm6yoGOpaxhOvKQMw7dXUPsLvbCyw/6dZOLvaFhjJjQiXtbxtZG+UjR8nvA== - dependencies: - "@storybook/api" "6.0.26" - "@storybook/channels" "6.0.26" - "@storybook/client-logger" "6.0.26" - "@storybook/core-events" "6.0.26" - "@storybook/router" "6.0.26" - "@storybook/theming" "6.0.26" - core-js "^3.0.1" - global "^4.3.2" - regenerator-runtime "^0.13.3" - -"@storybook/api@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/api/-/api-6.0.21.tgz#a25a1eb4d07dc43500e03c856db43baba46726f1" - integrity sha512-cRRGf/KGFwYiDouTouEcDdp45N1AbYnAfvLqYZ3KuUTGZ+CiU/PN/vavkp07DQeM4FIQO8TLhzHdsLFpLT7Lkw== +"@storybook/api@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/api/-/api-6.1.11.tgz#1e0b798203df823ac21184386258cf8b5f17f440" + integrity sha512-/p4QW/p3uWO0AKVveNezX3I/CotyBKaJ5ui8PuvSPsl7yvqcsK41qI4evKOw7GMQn6oP+2enRbzHpGuCUgQSjA== dependencies: "@reach/router" "^1.3.3" - "@storybook/channels" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/core-events" "6.0.21" + "@storybook/channels" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/core-events" "6.1.11" "@storybook/csf" "0.0.1" - "@storybook/router" "6.0.21" + "@storybook/router" "6.1.11" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.21" + "@storybook/theming" "6.1.11" "@types/reach__router" "^1.3.5" core-js "^3.0.1" fast-deep-equal "^3.1.1" global "^4.3.2" lodash "^4.17.15" memoizerific "^1.11.3" - react "^16.8.3" - regenerator-runtime "^0.13.3" + regenerator-runtime "^0.13.7" store2 "^2.7.1" telejson "^5.0.2" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/api@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/api/-/api-6.0.26.tgz#c45222c132eb8bc2e383536adfebbeb7a89867d0" - integrity sha512-aszDoz1c6T+eRtTUwWvySoyd3gRXmQxsingD084NnEp4VfFLA5H7VS/0sre0ZvU5GWh8d9COxY0DS2Ry/QSKvw== +"@storybook/channel-postmessage@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.1.11.tgz#62c1079f04870dd27925bd538a2020e7380daa2e" + integrity sha512-voW4Z2SUacDOxwN2q1NEBL//8OpgvL2C5CeoG1VQyEllKM8Vg9t1Nxo2FFTJBzv5LeEX7VIJKeBoB25DYvKyng== dependencies: - "@reach/router" "^1.3.3" - "@storybook/channels" "6.0.26" - "@storybook/client-logger" "6.0.26" - "@storybook/core-events" "6.0.26" - "@storybook/csf" "0.0.1" - "@storybook/router" "6.0.26" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.26" - "@types/reach__router" "^1.3.5" - core-js "^3.0.1" - fast-deep-equal "^3.1.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - react "^16.8.3" - regenerator-runtime "^0.13.3" - store2 "^2.7.1" - telejson "^5.0.2" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/channel-postmessage@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.0.21.tgz#97e8f43c1b66f84c7b8271e447d45d4f66d355d1" - integrity sha512-ArRnoaS+b7qpAku/SO27z/yjRDCXb37mCPYGX0ntPbiQajootUbGO7otfnjFkaP44hCEC9uDYlOfMU1hYU1N6A== - dependencies: - "@storybook/channels" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/core-events" "6.0.21" + "@storybook/channels" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/core-events" "6.1.11" core-js "^3.0.1" global "^4.3.2" qs "^6.6.0" telejson "^5.0.2" -"@storybook/channel-postmessage@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.0.26.tgz#a98a0132d6bdf06741afac2607e9feabe34ab98b" - integrity sha512-FT6lC8M5JlNBxPT0rYfmF1yl9mBv04nfYs82TZpp1CzpLxf7wxdCBZ8SSRmvWIVBoNwGZPDhIk5+6JWyDEISBg== - dependencies: - "@storybook/channels" "6.0.26" - "@storybook/client-logger" "6.0.26" - "@storybook/core-events" "6.0.26" - core-js "^3.0.1" - global "^4.3.2" - qs "^6.6.0" - telejson "^5.0.2" - -"@storybook/channels@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.0.21.tgz#bc0951efacbaa5f8827693fba4fe7c2290b5772c" - integrity sha512-G6gjcEotSwDmOlxSmOMgsO3VhQ42RLJK7kFp6D5eg0Q6S8vsypltdT8orxdu+6+AbcBrL+5Sla8lThzaCvXsVQ== +"@storybook/channels@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.1.11.tgz#a93a83746ad78dd40e1c056029f6d93b17bb66bc" + integrity sha512-NvjWzQ95TSV1e18jaQBCOGoe+vptKH2NOKZ7QRQ7I0O5OoHKr47IXoh+MQ5C8CRD9FTdLE/xWdn1sVVEPRyHEw== dependencies: core-js "^3.0.1" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/channels@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.0.26.tgz#3e8678b4b40085081257a39b9e85fab13a19943c" - integrity sha512-H0iUorayYqS+zfhbjd+cYRzAdRLGLWUeWFu2Aa+oJ4/zeAQNL+DafWboHc567RQ4Vb5KqE5QZoCFskWUUYqJYA== +"@storybook/client-api@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.1.11.tgz#d25aac484ca84a1acb01d450e756a62408f00c1a" + integrity sha512-DodJQzGCR+PYs26klvbquTjfBgkw5nvCZd3jpgWQtOrYaY/cMY1LLkVkKqrm2ENW8f7vf7tiw78RtxaXy7xeIQ== dependencies: - core-js "^3.0.1" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/client-api@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.0.21.tgz#6a652dea67d219a31d18af0e05b9f17ba6c7c316" - integrity sha512-emBXd/ml6pc3G8gP3MsR9zQsAq1zZbqof9MxB51tG/jpTXdqWQ8ce1pt1tJS8Xj0QDM072jR6wsY+mmro0GZnA== - dependencies: - "@storybook/addons" "6.0.21" - "@storybook/channel-postmessage" "6.0.21" - "@storybook/channels" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/core-events" "6.0.21" + "@storybook/addons" "6.1.11" + "@storybook/channel-postmessage" "6.1.11" + "@storybook/channels" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/core-events" "6.1.11" "@storybook/csf" "0.0.1" "@types/qs" "^6.9.0" - "@types/webpack-env" "^1.15.2" + "@types/webpack-env" "^1.15.3" core-js "^3.0.1" global "^4.3.2" lodash "^4.17.15" memoizerific "^1.11.3" qs "^6.6.0" + regenerator-runtime "^0.13.7" stable "^0.1.8" store2 "^2.7.1" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-api@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.0.26.tgz#ac9334ba86834e5cb23fc4fb577de60bda66164d" - integrity sha512-Qd5wR5b5lio/EchuJMhAmmJAE1pfvnEyu+JnyFGwMZLV9mN9NSspz+YsqbSCCDZsYcP5ewvPEnumIWqmj/wagQ== +"@storybook/client-logger@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.1.11.tgz#5dd092e4293e5f58f7e89ddbc6eb2511b7d60954" + integrity sha512-dSc+VKLW1UaiMPMhlZYRqhynrrHdHFiBEgU28+8LcmoZ1yhZBwLkcKdSD4YTT0CbMJAG1/+NUW5kRI8Geeg+rA== dependencies: - "@storybook/addons" "6.0.26" - "@storybook/channel-postmessage" "6.0.26" - "@storybook/channels" "6.0.26" - "@storybook/client-logger" "6.0.26" - "@storybook/core-events" "6.0.26" + core-js "^3.0.1" + global "^4.3.2" + +"@storybook/components@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/components/-/components-6.1.11.tgz#edd5db7fe43f47b5a7ab515840795a89d931512e" + integrity sha512-DGDl76uONTkg0rpsa36TpVuXv4K7rFYe8GnQ/Q8n4By5tvldC4s9YXwcDRYHVrfnYybKzuZ/+jv2ZAp4/8ZaeA== + dependencies: + "@popperjs/core" "^2.5.4" + "@storybook/client-logger" "6.1.11" "@storybook/csf" "0.0.1" - "@types/qs" "^6.9.0" - "@types/webpack-env" "^1.15.2" - core-js "^3.0.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - qs "^6.6.0" - stable "^0.1.8" - store2 "^2.7.1" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/client-logger@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.0.21.tgz#20369addf9eb79fc0c85a2e0dcb48f5a1a544532" - integrity sha512-8aUEbhjXV+UMYQWukVYnp+kZafF+LD4Dm7eMo37IUZvt3VIjV1VvhxIDVJtqjk2vv0KZTepESFBkZQLmBzI9Zg== - dependencies: - core-js "^3.0.1" - global "^4.3.2" - -"@storybook/client-logger@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.0.26.tgz#e3d28bd8dc02ec2c53a9d69773a68189590b746f" - integrity sha512-VNoL6/oehVhn3hZi9vrTNT+C/3oAZKV+smfZFnPtsCR/Fq7CKbmsBd0pGPL57f81RU8e8WygwrIlAGJTDSNIjw== - dependencies: - core-js "^3.0.1" - global "^4.3.2" - -"@storybook/components@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/components/-/components-6.0.21.tgz#2f355370f993e0b7b9062094a03dffc2cdda91db" - integrity sha512-r6btqFW/rcXIU5v231EifZfdh9O0fy7bJDXwwDf8zVUgLx8JRc0VnSs3nvK3Is9HF1wZ9vjx/7Lh4rTIDZAjgg== - dependencies: - "@storybook/client-logger" "6.0.21" - "@storybook/csf" "0.0.1" - "@storybook/theming" "6.0.21" + "@storybook/theming" "6.1.11" "@types/overlayscrollbars" "^1.9.0" "@types/react-color" "^3.0.1" "@types/react-syntax-highlighter" "11.0.4" @@ -4618,97 +4579,60 @@ memoizerific "^1.11.3" overlayscrollbars "^1.10.2" polished "^3.4.4" - popper.js "^1.14.7" - react "^16.8.3" react-color "^2.17.0" - react-dom "^16.8.3" - react-popper-tooltip "^2.11.0" - react-syntax-highlighter "^12.2.1" + react-popper-tooltip "^3.1.1" + react-syntax-highlighter "^13.5.0" react-textarea-autosize "^8.1.1" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" -"@storybook/components@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/components/-/components-6.0.26.tgz#e1f6e16aae850a71c9ac7bdd1d44a068ec9cfdc1" - integrity sha512-8wigI1pDFJO1m1IQWPguOK+nOsaAVRWkVdu+2te/rDcIR9QNvMzzou0+Lhfp3zKSVT4E6mEoGB/TWXXF5Iq0sQ== - dependencies: - "@storybook/client-logger" "6.0.26" - "@storybook/csf" "0.0.1" - "@storybook/theming" "6.0.26" - "@types/overlayscrollbars" "^1.9.0" - "@types/react-color" "^3.0.1" - "@types/react-syntax-highlighter" "11.0.4" - core-js "^3.0.1" - fast-deep-equal "^3.1.1" - global "^4.3.2" - lodash "^4.17.15" - markdown-to-jsx "^6.11.4" - memoizerific "^1.11.3" - overlayscrollbars "^1.10.2" - polished "^3.4.4" - popper.js "^1.14.7" - react "^16.8.3" - react-color "^2.17.0" - react-dom "^16.8.3" - react-popper-tooltip "^2.11.0" - react-syntax-highlighter "^12.2.1" - react-textarea-autosize "^8.1.1" - ts-dedent "^1.1.1" - -"@storybook/core-events@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.0.21.tgz#2ce51e6d7524e7543dbb29571beac1dbeb4e5f40" - integrity sha512-p84fbPcsAhnqDhp+HJ4P8+vI2BqJus4IRoVAemLAwuPjyPElrV9UvOa/RHy1BN8Z6jXwFA+FFzfGl2kPJ3WYcA== +"@storybook/core-events@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.1.11.tgz#d50e8ec90490f9a7180a8c8a83afb6dcfe47ed66" + integrity sha512-hTib81W8PxepM7iXVvl3pBXSaGpChl5LTzaLCoIRO9sSB8dy0/x2DLAHzbQvShk/l1wqUc3TtOLIxq+eC9l3wg== dependencies: core-js "^3.0.1" -"@storybook/core-events@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.0.26.tgz#61181c9a8610d26cc85d47f133a563879044ca2d" - integrity sha512-nWjS/+kMiw31OPgeJQaiFsJk9ZJJo3/d4c+kc6GOl2iC1H3Q4/5cm3NvJBn/7bUtKHmSFwfbDouj+XjUk5rZbQ== +"@storybook/core@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/core/-/core-6.1.11.tgz#ed9d3b513794c604ab11180f6a014924b871179e" + integrity sha512-pYOOQwiNJ5myLRn6p6nnLUjjjISHK/N55vS4HFnETYSaRLA++h1coN1jk7Zwt89dOQTdF0EsTJn+6snYOC+lxQ== dependencies: - core-js "^3.0.1" - -"@storybook/core@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/core/-/core-6.0.21.tgz#105c2b90ab27e7b478cb1b7d10e9fe5aba5e0708" - integrity sha512-/Et5NLabB12dnuPdhHDA/Q1pj0Mm2DGdL3KiLO4IC2VZeICCLGmU3/EGJBgjLK+anQ59pkclOiQ8i9eMXFiJ6A== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.8.3" - "@babel/plugin-proposal-decorators" "^7.8.3" - "@babel/plugin-proposal-export-default-from" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" - "@babel/plugin-proposal-object-rest-spread" "^7.9.6" - "@babel/plugin-proposal-optional-chaining" "^7.10.1" - "@babel/plugin-proposal-private-methods" "^7.8.3" + "@babel/core" "^7.12.3" + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-decorators" "^7.12.1" + "@babel/plugin-proposal-export-default-from" "^7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-object-rest-spread" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.1" + "@babel/plugin-proposal-private-methods" "^7.12.1" "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.5" - "@babel/plugin-transform-destructuring" "^7.9.5" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-parameters" "^7.9.5" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/preset-env" "^7.9.6" - "@babel/preset-react" "^7.8.3" - "@babel/preset-typescript" "^7.9.0" - "@babel/register" "^7.10.5" - "@storybook/addons" "6.0.21" - "@storybook/api" "6.0.21" - "@storybook/channel-postmessage" "6.0.21" - "@storybook/channels" "6.0.21" - "@storybook/client-api" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/components" "6.0.21" - "@storybook/core-events" "6.0.21" + "@babel/plugin-transform-arrow-functions" "^7.12.1" + "@babel/plugin-transform-block-scoping" "^7.12.1" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-destructuring" "^7.12.1" + "@babel/plugin-transform-for-of" "^7.12.1" + "@babel/plugin-transform-parameters" "^7.12.1" + "@babel/plugin-transform-shorthand-properties" "^7.12.1" + "@babel/plugin-transform-spread" "^7.12.1" + "@babel/plugin-transform-template-literals" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.1" + "@babel/preset-typescript" "^7.12.1" + "@babel/register" "^7.12.1" + "@storybook/addons" "6.1.11" + "@storybook/api" "6.1.11" + "@storybook/channel-postmessage" "6.1.11" + "@storybook/channels" "6.1.11" + "@storybook/client-api" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/components" "6.1.11" + "@storybook/core-events" "6.1.11" "@storybook/csf" "0.0.1" - "@storybook/node-logger" "6.0.21" - "@storybook/router" "6.0.21" + "@storybook/node-logger" "6.1.11" + "@storybook/router" "6.1.11" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.21" - "@storybook/ui" "6.0.21" + "@storybook/theming" "6.1.11" + "@storybook/ui" "6.1.11" "@types/glob-base" "^0.3.0" "@types/micromatch" "^4.0.1" "@types/node-fetch" "^2.5.4" @@ -4726,6 +4650,7 @@ cli-table3 "0.6.0" commander "^5.0.0" core-js "^3.0.1" + cpy "^8.1.1" css-loader "^3.5.3" detect-port "^1.3.0" dotenv-webpack "^1.7.0" @@ -4756,19 +4681,21 @@ qs "^6.6.0" raw-loader "^4.0.1" react-dev-utils "^10.0.0" - regenerator-runtime "^0.13.3" + regenerator-runtime "^0.13.7" resolve-from "^5.0.0" serve-favicon "^2.5.0" - shelljs "^0.8.3" + shelljs "^0.8.4" stable "^0.1.8" style-loader "^1.2.1" + telejson "^5.0.2" terser-webpack-plugin "^3.0.0" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" unfetch "^4.1.0" url-loader "^4.0.0" util-deprecate "^1.0.2" - webpack "^4.43.0" + webpack "^4.44.2" webpack-dev-middleware "^3.7.0" + webpack-filter-warnings-plugin "^1.2.1" webpack-hot-middleware "^2.25.0" webpack-virtual-modules "^0.2.2" @@ -4779,10 +4706,10 @@ dependencies: lodash "^4.17.15" -"@storybook/node-logger@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.0.21.tgz#5b8ba589d5cca6a67c69ee8f5258755b7e1dbc08" - integrity sha512-KRBf+Fz7fgtwHdnYt70JTZbcYMZ1pQPtDyqbrFYCjwkbx5GPX5vMOozlxCIj9elseqPIsF8CKgHOW7cFHVyWYw== +"@storybook/node-logger@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.1.11.tgz#8e0d058b4804f2fea03c9d7d331b8e2d02f3b7ff" + integrity sha512-MASonXDWpSMU9HF9mqbGOR1Ps/DTJ8AVmYD50+OnB9kXl4M42Dliobeq7JwKFMnZ42RelUCCSXdWW80hGrUKKA== dependencies: "@types/npmlog" "^4.1.2" chalk "^4.0.0" @@ -4790,48 +4717,37 @@ npmlog "^4.1.2" pretty-hrtime "^1.0.3" -"@storybook/react@^6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/react/-/react-6.0.21.tgz#68f8a318e9940305b06eb894896624a35a9868b0" - integrity sha512-L3PcoBJq5aK1aTaJNfwsSJ8Kxgcyk0WknN4TDqhP7a+oXmuMY1YEi96hEvQVIm0TBCkQxs61K70/T7vlilEtHg== +"@storybook/react@^6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/react/-/react-6.1.11.tgz#e94403cd878c66b445df993bad9bec9023db3ebe" + integrity sha512-EmR7yvVW6z6AYhfzAgJMGR/5+igeBGa1EePaEIibn51r5uboSB72N12NaADyF2OaycIdV+0sW6vP9Zvlvexa/w== dependencies: - "@babel/preset-flow" "^7.0.0" - "@babel/preset-react" "^7.0.0" - "@storybook/addons" "6.0.21" - "@storybook/core" "6.0.21" - "@storybook/node-logger" "6.0.21" + "@babel/preset-flow" "^7.12.1" + "@babel/preset-react" "^7.12.1" + "@pmmmwh/react-refresh-webpack-plugin" "^0.4.2" + "@storybook/addons" "6.1.11" + "@storybook/core" "6.1.11" + "@storybook/node-logger" "6.1.11" "@storybook/semver" "^7.3.2" - "@svgr/webpack" "^5.4.0" - "@types/webpack-env" "^1.15.2" + "@types/webpack-env" "^1.15.3" babel-plugin-add-react-displayname "^0.0.5" babel-plugin-named-asset-import "^0.3.1" - babel-plugin-react-docgen "^4.1.0" + babel-plugin-react-docgen "^4.2.1" core-js "^3.0.1" global "^4.3.2" lodash "^4.17.15" prop-types "^15.7.2" react-dev-utils "^10.0.0" - react-docgen-typescript-plugin "^0.5.2" - regenerator-runtime "^0.13.3" - ts-dedent "^1.1.1" - webpack "^4.43.0" + react-docgen-typescript-plugin "^0.6.2" + react-refresh "^0.8.3" + regenerator-runtime "^0.13.7" + ts-dedent "^2.0.0" + webpack "^4.44.2" -"@storybook/router@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/router/-/router-6.0.21.tgz#0f22261d4782c72a5a13e80cfcd8d50aed1f98c6" - integrity sha512-46SsKJfcd12lRrISnfrWhicJx8EylkgGDGohfH0n5p7inkkGOkKV8QFZoYPRKZueMXmUKpzJ0Z3HmVsLTCrCDw== - dependencies: - "@reach/router" "^1.3.3" - "@types/reach__router" "^1.3.5" - core-js "^3.0.1" - global "^4.3.2" - memoizerific "^1.11.3" - qs "^6.6.0" - -"@storybook/router@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/router/-/router-6.0.26.tgz#5b991001afa7d7eb5e40c53cd4c58266b6f9edfd" - integrity sha512-kQ1LF/2gX3IkjS1wX7CsoeBc9ptHQzOsyax16rUyJa769DT5vMNtFtQxjNXMqSiSapPg2yrXJFKQNaoWvKgQEQ== +"@storybook/router@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/router/-/router-6.1.11.tgz#d58e0c8324d8b16d71e09c017a4e3c844b1a4139" + integrity sha512-YEYOoKMo/WI13MZCkdqI9X3H1G0Oj5OUxi7So4qd3khX3zcCjSr3LjiMDBcmIVZpFo5VAvzjhIY4KqpgvzTG0A== dependencies: "@reach/router" "^1.3.3" "@types/reach__router" "^1.3.5" @@ -4848,13 +4764,13 @@ core-js "^3.6.5" find-up "^4.1.0" -"@storybook/source-loader@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.0.21.tgz#f4ae0fa3f3d119f9ace1d3364df21f8f7cf65bd7" - integrity sha512-Duzpz8udadR7wzH8/4F3GnMRe23oBOxTm4jBZw/T8NA+HqBtd9Y16swWw4BfwsRwfdZS4EVw3PtWgsAfoqF7ow== +"@storybook/source-loader@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.1.11.tgz#26e0ba30d5b9d1828ed10ccb76eb38bf48aad304" + integrity sha512-pEMWGn3XwZYAXwIrtmd7ziH5d1zN8NCpJM8vNJssntZFW45rDo69xgGM/PrTLPDca6f/Mhv+vqzR99tdfarJSw== dependencies: - "@storybook/addons" "6.0.21" - "@storybook/client-logger" "6.0.21" + "@storybook/addons" "6.1.11" + "@storybook/client-logger" "6.1.11" "@storybook/csf" "0.0.1" core-js "^3.0.1" estraverse "^4.2.0" @@ -4862,17 +4778,18 @@ loader-utils "^2.0.0" lodash "^4.17.15" prettier "~2.0.5" - regenerator-runtime "^0.13.3" + regenerator-runtime "^0.13.7" + source-map "^0.7.3" -"@storybook/theming@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.0.21.tgz#d56051c0b8679c2b701ce08385660ab4146cf15f" - integrity sha512-n97DfB9kG6WrV1xBGDyeQibTrh8pBBCp3dSL3UTGH+KX3C2+4sm6QHlTgyekbi5FrbFEbnuZOKAS3YbLVONsRQ== +"@storybook/theming@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.1.11.tgz#0e757e0562aedefc96bd1d12714d4c8e92823467" + integrity sha512-zRChacVgKoU2BmpvwK1ntiF3KIpc8QblJT7IGiKfP/BNpy9gNeXbLPLk3g/tkHszOvVYtkaZhEXni4Od8tqy1A== dependencies: - "@emotion/core" "^10.0.20" + "@emotion/core" "^10.1.1" "@emotion/is-prop-valid" "^0.8.6" - "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "6.0.21" + "@emotion/styled" "^10.0.23" + "@storybook/client-logger" "6.1.11" core-js "^3.0.1" deep-object-diff "^1.1.0" emotion-theming "^10.0.19" @@ -4880,45 +4797,28 @@ memoizerific "^1.11.3" polished "^3.4.4" resolve-from "^5.0.0" - ts-dedent "^1.1.1" + ts-dedent "^2.0.0" -"@storybook/theming@6.0.26": - version "6.0.26" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.0.26.tgz#e5b545fb2653dfd1b043b567197d490b1c3c0da3" - integrity sha512-9yon2ofb9a+RT1pdvn8Njydy7XRw0qXcIsMqGsJRKoZecmRRozqB6DxH9Gbdf1vRSbM9gYUUDjbiMDFz7+4RiQ== +"@storybook/ui@6.1.11": + version "6.1.11" + resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.1.11.tgz#2e5a5df010f2bb75a09a0fd0439fc8e62f8c89e5" + integrity sha512-Qth2dxS5+VbKHcqgkiKpeD+xr/hRUuUIDUA/2Ierh/BaA8Up/krlso/mCLaQOa5E8Og9WJAdDFO0cUbt939c2Q== dependencies: - "@emotion/core" "^10.0.20" - "@emotion/is-prop-valid" "^0.8.6" - "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "6.0.26" - core-js "^3.0.1" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.19" - global "^4.3.2" - memoizerific "^1.11.3" - polished "^3.4.4" - resolve-from "^5.0.0" - ts-dedent "^1.1.1" - -"@storybook/ui@6.0.21": - version "6.0.21" - resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.0.21.tgz#5dac2b68a30f5dba5457e0315f58977e07138968" - integrity sha512-50QYF8tHUgpVq7B7PWp7kmyf79NySWJO0piQFjHv027vV8GfbXMWVswAXwo3IfCihPlnLKe01WbsigM/9T1HCQ== - dependencies: - "@emotion/core" "^10.0.20" - "@storybook/addons" "6.0.21" - "@storybook/api" "6.0.21" - "@storybook/channels" "6.0.21" - "@storybook/client-logger" "6.0.21" - "@storybook/components" "6.0.21" - "@storybook/core-events" "6.0.21" - "@storybook/router" "6.0.21" + "@emotion/core" "^10.1.1" + "@storybook/addons" "6.1.11" + "@storybook/api" "6.1.11" + "@storybook/channels" "6.1.11" + "@storybook/client-logger" "6.1.11" + "@storybook/components" "6.1.11" + "@storybook/core-events" "6.1.11" + "@storybook/router" "6.1.11" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.21" + "@storybook/theming" "6.1.11" "@types/markdown-to-jsx" "^6.11.0" copy-to-clipboard "^3.0.8" core-js "^3.0.1" core-js-pure "^3.0.1" + downshift "^6.0.6" emotion-theming "^10.0.19" fuse.js "^3.6.1" global "^4.3.2" @@ -4927,13 +4827,11 @@ memoizerific "^1.11.3" polished "^3.4.4" qs "^6.6.0" - react "^16.8.3" - react-dom "^16.8.3" react-draggable "^4.0.3" react-helmet-async "^1.0.2" react-hotkeys "2.0.0" react-sizeme "^2.6.7" - regenerator-runtime "^0.13.3" + regenerator-runtime "^0.13.7" resolve-from "^5.0.0" store2 "^2.7.1" @@ -5191,7 +5089,7 @@ "@svgr/plugin-svgo" "^5.5.0" rollup-pluginutils "^2.8.2" -"@svgr/webpack@5.4.x", "@svgr/webpack@^5.4.0": +"@svgr/webpack@5.4.x": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.4.0.tgz#b68bc86e29cf007292b96ced65f80971175632e0" integrity sha512-LjepnS/BSAvelnOnnzr6Gg0GcpLmnZ9ThGFK5WJtm1xOqdBE/1IACZU7MMdVzjyUkfFqGz87eRE4hFaSLiUwYg== @@ -5989,6 +5887,11 @@ dependencies: "@types/braces" "*" +"@types/mime-types@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73" + integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM= + "@types/mime@*": version "2.0.1" resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" @@ -6566,6 +6469,11 @@ resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.15.3.tgz#fb602cd4c2f0b7c0fb857e922075fdf677d25d84" integrity sha512-5oiXqR7kwDGZ6+gmzIO2lTC+QsriNuQXZDWNYRV3l2XRN/zmPgnC21DLSx2D05zvD8vnXW6qUg7JnXZ4I6qLVQ== +"@types/webpack-env@^1.15.3": + version "1.16.0" + resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz#8c0a9435dfa7b3b1be76562f3070efb3f92637b4" + integrity sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw== + "@types/webpack-node-externals@^2.5.0": version "2.5.0" resolved "https://registry.npmjs.org/@types/webpack-node-externals/-/webpack-node-externals-2.5.0.tgz#bcd161af84a4960416e5850e06931b35321c6654" @@ -6906,18 +6814,6 @@ "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" -"@webpack-contrib/schema-utils@^1.0.0-beta.0": - version "1.0.0-beta.0" - resolved "https://registry.npmjs.org/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" - integrity sha512-LonryJP+FxQQHsjGBi6W786TQB1Oym+agTpY0c+Kj8alnIw+DLUJb6SI8Y1GHGhLCH1yPRrucjObUmxNICQ1pg== - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chalk "^2.3.2" - strip-ansi "^4.0.0" - text-table "^0.2.0" - webpack-log "^1.1.2" - "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -7168,7 +7064,7 @@ ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1: dependencies: type-fest "^0.11.0" -ansi-html@0.0.7: +ansi-html@0.0.7, ansi-html@^0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= @@ -7490,9 +7386,9 @@ archiver-utils@^2.1.0: readable-stream "^2.0.0" archiver@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/archiver/-/archiver-5.0.2.tgz#b2c435823499b1f46eb07aa18e7bcb332f6ca3fc" - integrity sha512-Tq3yV/T4wxBsD2Wign8W9VQKhaUxzzRmjEiSoOK0SLqPgDP/N1TKdYyBeIEu56T4I9iO4fKTTR0mN9NWkBA0sg== + version "5.1.0" + resolved "https://registry.npmjs.org/archiver/-/archiver-5.1.0.tgz#05b0f6f7836f3e6356a0532763d2bb91017a7e37" + integrity sha512-iKuQUP1nuKzBC2PFlGet5twENzCfyODmvkxwDV0cEFXavwcLrIW5ssTuHi9dyTPvpWr6Faweo2eQaQiLIwyXTA== dependencies: archiver-utils "^2.1.0" async "^3.2.0" @@ -7500,7 +7396,7 @@ archiver@^5.0.2: readable-stream "^3.6.0" readdir-glob "^1.0.0" tar-stream "^2.1.4" - zip-stream "^4.0.0" + zip-stream "^4.0.4" are-we-there-yet@~1.1.2: version "1.1.5" @@ -7715,16 +7611,18 @@ ast-types-flow@0.0.7, ast-types-flow@^0.0.7: resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= -ast-types@0.11.3: - version "0.11.3" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" - integrity sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA== - ast-types@^0.13.2: version "0.13.2" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== +ast-types@^0.14.2: + version "0.14.2" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" + integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== + dependencies: + tslib "^2.0.1" + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -8060,14 +7958,14 @@ babel-plugin-named-asset-import@^0.3.1: resolved "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz#c9750a1b38d85112c9e166bf3ef7c5dbc605f4be" integrity sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA== -babel-plugin-react-docgen@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.1.0.tgz#1dfa447dac9ca32d625a123df5733a9e47287c26" - integrity sha512-vzpnBlfGv8XOhJM2zbPyyqw2OLEbelgZZsaaRRTpVwNKuYuc+pUg4+dy7i9gCRms0uOQn4osX571HRcCJMJCmA== +babel-plugin-react-docgen@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b" + integrity sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ== dependencies: + ast-types "^0.14.2" lodash "^4.17.15" react-docgen "^5.0.0" - recast "^0.14.7" babel-plugin-syntax-jsx@^6.18.0: version "6.18.0" @@ -8390,7 +8288,7 @@ bl@^1.0.0: readable-stream "^2.3.5" safe-buffer "^5.1.1" -bl@^4.0.1, bl@^4.0.3: +bl@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== @@ -8715,14 +8613,6 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.1.0: - version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - buffer@^5.5.0: version "5.6.0" resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" @@ -9062,7 +8952,7 @@ chainsaw@~0.1.0: dependencies: traverse ">=0.3.0 <0.4" -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -9609,13 +9499,13 @@ component-emitter@^1.2.0, component-emitter@^1.2.1: resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compress-commons@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.1.tgz#c5fa908a791a0c71329fba211d73cd2a32005ea8" - integrity sha512-xZm9o6iikekkI0GnXCmAl3LQGZj5TBDj0zLowsqi7tJtEa3FMGSEcHcqrSJIrOAk1UG/NBbDn/F1q+MG/p/EsA== +compress-commons@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.2.tgz#d6896be386e52f37610cef9e6fa5defc58c31bd7" + integrity sha512-qhd32a9xgzmpfoga1VQEiLEwdKZ6Plnpx5UCgIsf89FSolyJ7WnifY4Gtjgv5WR6hWAyRaHxC5MiEhU/38U70A== dependencies: buffer-crc32 "^0.2.13" - crc32-stream "^4.0.0" + crc32-stream "^4.0.1" normalize-path "^3.0.0" readable-stream "^3.6.0" @@ -9658,6 +9548,11 @@ compute-lcm@^1.1.0: validate.io-function "^1.0.2" validate.io-integer-array "^1.0.0" +compute-scroll-into-view@^1.0.16: + version "1.0.16" + resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088" + integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -9986,20 +9881,46 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -crc32-stream@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.0.tgz#05b7ca047d831e98c215538666f372b756d91893" - integrity sha512-tyMw2IeUX6t9jhgXI6um0eKfWq4EIDpfv5m7GX4Jzp7eVelQ360xd8EPXJhp2mHwLQIkqlnMLjzqSZI3a+0wRw== +cp-file@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" + integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== dependencies: - crc "^3.4.4" - readable-stream "^3.4.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + nested-error-stacks "^2.0.0" + p-event "^4.1.0" -crc@^3.4.4: - version "3.8.0" - resolved "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" - integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== +cpy@^8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/cpy/-/cpy-8.1.1.tgz#066ed4c6eaeed9577df96dae4db9438c1a90df62" + integrity sha512-vqHT+9o67sMwJ5hUd/BAOYeemkU+MuFRsK2c36Xc3eefQpAsp1kAsyDxEDcc5JS1+y9l/XHPrIsVTcyGGmkUUQ== dependencies: - buffer "^5.1.0" + arrify "^2.0.1" + cp-file "^7.0.0" + globby "^9.2.0" + has-glob "^1.0.0" + junk "^3.1.0" + nested-error-stacks "^2.1.0" + p-all "^2.1.0" + p-filter "^2.1.0" + p-map "^3.0.0" + +crc-32@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +crc32-stream@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.1.tgz#0f047d74041737f8a55e86837a1b826bd8ab0067" + integrity sha512-FN5V+weeO/8JaXsamelVYO1PHyeCsuL3HcG4cqsj0ceARcocxalaShCsohZMSAF+db7UYFwBy1rARK/0oFItUw== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" create-ecdh@^4.0.0: version "4.0.3" @@ -10040,7 +9961,7 @@ create-react-class@^15.5.1: loose-envify "^1.3.1" object-assign "^4.1.1" -create-react-context@0.3.0, create-react-context@^0.3.0: +create-react-context@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== @@ -10814,7 +10735,7 @@ dedent@^0.7.0: resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-equal@^1.0.1, deep-equal@^1.1.1: +deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== @@ -11327,6 +11248,16 @@ dotenv@^8.0.0, dotenv@^8.2.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +downshift@^6.0.6: + version "6.0.7" + resolved "https://registry.npmjs.org/downshift/-/downshift-6.0.7.tgz#05ef58b991e4467cdb8cd36e7a87a011d0bada5c" + integrity sha512-+rqgx3JTSs8b4V9q++hsLvaP8mhMOdX7u+jy5S2etg7+Y7uFLVzZaI0S7Xo2yEnNDmTcNnYZZ/vFjdWuJ2kZdg== + dependencies: + "@babel/runtime" "^7.12.5" + compute-scroll-into-view "^1.0.16" + prop-types "^15.7.2" + react-is "^17.0.1" + duplexer2@~0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" @@ -11987,7 +11918,7 @@ espree@^7.3.0: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -12188,6 +12119,11 @@ exit-hook@^1.0.0: resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + exit@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -12455,7 +12391,7 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fault@^1.0.0, fault@^1.0.2: +fault@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== @@ -13252,10 +13188,10 @@ git-url-parse@^11.1.2: dependencies: git-up "^4.0.0" -git-url-parse@^11.4.0: - version "11.4.0" - resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.0.tgz#f2bb1f2b00f05552540e95a62e31399a639a6aa6" - integrity sha512-KlIa5jvMYLjXMQXkqpFzobsyD/V2K5DRHl5OAf+6oDFPlPLxrGDVQlIdI63c4/Kt6kai4kALENSALlzTGST3GQ== +git-url-parse@^11.4.3: + version "11.4.3" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.3.tgz#1610284edf1f14964180f5b3399ec68b692cfd87" + integrity sha512-LZTTk0nqJnKN48YRtOpR8H5SEfp1oM2tls90NuZmBxN95PnCvmuXGzqQ4QmVirBgKx2KPYfPGteX3/raWjKenQ== dependencies: git-up "^4.0.0" @@ -13757,10 +13693,10 @@ graphql-upload@^8.0.2: http-errors "^1.7.3" object-path "^0.11.4" -graphql@15.3.0, graphql@^15.3.0: - version "15.3.0" - resolved "https://registry.npmjs.org/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" - integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w== +graphql@15.4.0, graphql@^15.3.0: + version "15.4.0" + resolved "https://registry.npmjs.org/graphql/-/graphql-15.4.0.tgz#e459dea1150da5a106486ba7276518b5295a4347" + integrity sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA== graphql@^14.5.3: version "14.7.0" @@ -13854,6 +13790,13 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" + integrity sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc= + dependencies: + is-glob "^3.0.0" + has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" @@ -13984,11 +13927,6 @@ highlight.js@^10.4.1, highlight.js@~10.4.0: resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0" integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg== -highlight.js@~9.15.0, highlight.js@~9.15.1: - version "9.15.10" - resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" - integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== - history@^4.9.0: version "4.10.1" resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" @@ -14085,6 +14023,11 @@ html-entities@^1.2.0, html-entities@^1.3.1: resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== +html-entities@^1.2.1: + version "1.3.3" + resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.3.3.tgz#3dca638a43ee7de316fc23067398491152ad4736" + integrity sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg== + html-escaper@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.1.tgz#beed86b5d2b921e92533aa11bce6d8e3b583dee7" @@ -14322,9 +14265,9 @@ humanize-ms@^1.2.1: ms "^2.0.0" husky@^4.2.3: - version "4.3.0" - resolved "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz#0b2ec1d66424e9219d359e26a51c58ec5278f0de" - integrity sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA== + version "4.3.6" + resolved "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz#ebd9dd8b9324aa851f1587318db4cccb7665a13c" + integrity sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag== dependencies: chalk "^4.0.0" ci-info "^2.0.0" @@ -14931,7 +14874,7 @@ is-glob@^2.0.0: dependencies: is-extglob "^1.0.0" -is-glob@^3.1.0: +is-glob@^3.0.0, is-glob@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= @@ -16199,6 +16142,11 @@ jsx-ast-utils@^2.2.1: array-includes "^3.1.1" object.assign "^4.1.1" +junk@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" + integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== + jwa@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -16847,13 +16795,6 @@ log-symbols@^1.0.2: dependencies: chalk "^1.0.0" -log-symbols@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - log-symbols@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" @@ -16903,14 +16844,6 @@ loglevel@^1.6.7, loglevel@^1.6.8: resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== -loglevelnext@^1.0.1: - version "1.0.5" - resolved "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" - integrity sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A== - dependencies: - es6-symbol "^3.1.1" - object.assign "^4.1.0" - long@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -16953,14 +16886,6 @@ lowercase-keys@^2.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== -lowlight@1.12.1: - version "1.12.1" - resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.12.1.tgz#014acf8dd73a370e02ff1cc61debcde3bb1681eb" - integrity sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w== - dependencies: - fault "^1.0.2" - highlight.js "~9.15.0" - lowlight@^1.14.0: version "1.14.0" resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.14.0.tgz#83ebc143fec0f9e6c0d3deffe01be129ce56b108" @@ -17501,7 +17426,7 @@ mime-db@1.44.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== -mime-types@^2.0.8, mime-types@^2.1.12, mime-types@^2.1.26, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: +mime-types@^2.0.8, mime-types@^2.1.12, mime-types@^2.1.26, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.27" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== @@ -17928,6 +17853,13 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +native-url@^0.2.6: + version "0.2.6" + resolved "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" + integrity sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA== + dependencies: + querystring "^0.2.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -17952,6 +17884,11 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== +nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" + integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== + next-tick@1: version "1.1.0" resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" @@ -18758,6 +18695,13 @@ overlayscrollbars@^1.10.2: resolved "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.0.tgz#1edb436328133b94877b558f77966d5497ca36a7" integrity sha512-p8oHrMeRAKxXDMPI/EBNITj/zTVHKNnAnM59Im+xnoZUlV07FyTg46wom2286jJlXGGfcPFG/ba5NUiCwWNd4w== +p-all@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" + integrity sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA== + dependencies: + p-map "^2.0.0" + p-any@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/p-any/-/p-any-3.0.0.tgz#79847aeed70b5d3a10ea625296c0c3d2e90a87b9" @@ -18781,7 +18725,7 @@ p-each-series@^2.1.0: resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== -p-event@^4.0.0: +p-event@^4.0.0, p-event@^4.1.0: version "4.2.0" resolved "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== @@ -19017,18 +18961,6 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-entities@^1.1.2: - version "1.2.2" - resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" - integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -19606,11 +19538,6 @@ popper.js@1.16.1-lts: resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== -popper.js@^1.14.4, popper.js@^1.14.7: - version "1.16.1" - resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - portfinder@^1.0.26: version "1.0.28" resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -20137,7 +20064,12 @@ pretty-hrtime@^1.0.3: resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -prismjs@^1.21.0, prismjs@^1.8.4, prismjs@~1.21.0: +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + +prismjs@^1.21.0, prismjs@~1.21.0: version "1.21.0" resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz#36c086ec36b45319ec4218ee164c110f9fc015a3" integrity sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw== @@ -20151,14 +20083,7 @@ prismjs@^1.22.0, prismjs@~1.22.0: optionalDependencies: clipboard "^2.0.0" -prismjs@~1.17.0: - version "1.17.1" - resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" - integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q== - optionalDependencies: - clipboard "^2.0.0" - -private@^0.1.8, private@~0.1.5: +private@^0.1.8: version "0.1.8" resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -20642,31 +20567,21 @@ react-dev-utils@^10.0.0, react-dev-utils@^10.2.1: strip-ansi "6.0.0" text-table "0.2.0" -react-docgen-typescript-loader@^3.7.2: - version "3.7.2" - resolved "https://registry.npmjs.org/react-docgen-typescript-loader/-/react-docgen-typescript-loader-3.7.2.tgz#45cb2305652c0602767242a8700ad1ebd66bbbbd" - integrity sha512-fNzUayyUGzSyoOl7E89VaPKJk9dpvdSgyXg81cUkwy0u+NBvkzQG3FC5WBIlXda0k/iaxS+PWi+OC+tUiGxzPA== - dependencies: - "@webpack-contrib/schema-utils" "^1.0.0-beta.0" - loader-utils "^1.2.3" - react-docgen-typescript "^1.15.0" - -react-docgen-typescript-plugin@^0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.5.2.tgz#2b294d75ef3145c36303da82be5d447cb67dc0dc" - integrity sha512-NQfWyWLmzUnedkiN2nPDb6Nkm68ik6fqbC3UvgjqYSeZsbKijXUA4bmV6aU7qICOXdop9PevPdjEgJuAN0nNVQ== +react-docgen-typescript-plugin@^0.6.2: + version "0.6.3" + resolved "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.6.3.tgz#664b22601df083597ecb1e60bd21beca60125fdf" + integrity sha512-av1S/fmWBNFGgNa4qtkidFjjOz23eEi6EdCtwSWo9WNhGzUMyMygbD/DosMWoeFlZpk9R3MXPkRE7PDH6j5GMQ== dependencies: debug "^4.1.1" endent "^2.0.1" micromatch "^4.0.2" - react-docgen-typescript "^1.20.1" - react-docgen-typescript-loader "^3.7.2" + react-docgen-typescript "^1.20.5" tslib "^2.0.0" -react-docgen-typescript@^1.15.0, react-docgen-typescript@^1.20.1: - version "1.20.4" - resolved "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.20.4.tgz#9a5655986077ccfc58c1a447f92c3d19f7a875bf" - integrity sha512-gE2SeseJd6+o981qr9VQJRbvFJ5LjLSKQiwhHsuLN4flt+lheKtG1jp2BPzrv2MKR5gmbLwpmNtK4wbLCPSZAw== +react-docgen-typescript@^1.20.5: + version "1.20.5" + resolved "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.20.5.tgz#fb8d78a707243498436c2952bd3f6f488a68d4f3" + integrity sha512-AbLGMtn76bn7SYBJSSaKJrZ0lgNRRR3qL60PucM5M4v/AXyC8221cKBXW5Pyt9TfDRfe+LDnPNlg7TibxX0ovA== react-docgen@^5.0.0: version "5.3.0" @@ -20682,7 +20597,7 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" -react-dom@^16.12.0, react-dom@^16.13.1, react-dom@^16.8.3: +react-dom@^16.12.0, react-dom@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== @@ -20715,7 +20630,7 @@ react-fast-compare@^2.0.4: resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== -react-fast-compare@^3.1.1: +react-fast-compare@^3.0.1, react-fast-compare@^3.1.1: version "3.2.0" resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== @@ -20852,25 +20767,21 @@ react-motion@^0.5.2: prop-types "^15.5.8" raf "^3.1.0" -react-popper-tooltip@^2.11.0: - version "2.11.1" - resolved "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644" - integrity sha512-04A2f24GhyyMicKvg/koIOQ5BzlrRbKiAgP6L+Pdj1MVX3yJ1NeZ8+EidndQsbejFT55oW1b++wg2Z8KlAyhfQ== +react-popper-tooltip@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac" + integrity sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ== dependencies: - "@babel/runtime" "^7.9.2" - react-popper "^1.3.7" + "@babel/runtime" "^7.12.5" + "@popperjs/core" "^2.5.4" + react-popper "^2.2.4" -react-popper@^1.3.7: - version "1.3.7" - resolved "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324" - integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww== +react-popper@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/react-popper/-/react-popper-2.2.4.tgz#d2ad3d2474ac9f1abf93df3099d408e5aa6a2e22" + integrity sha512-NacOu4zWupdQjVXq02XpTD3yFPSfg5a7fex0wa3uGKVkFK7UN6LvVxgcb+xYr56UCuWiNPMH20tntdVdJRwYew== dependencies: - "@babel/runtime" "^7.1.2" - create-react-context "^0.3.0" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" + react-fast-compare "^3.0.1" warning "^4.0.2" react-redux@=4.4.10: @@ -20896,6 +20807,11 @@ react-redux@^7.1.1: prop-types "^15.7.2" react-is "^16.9.0" +react-refresh@^0.8.3: + version "0.8.3" + resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" + integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== + react-resize-detector@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c" @@ -20989,16 +20905,16 @@ react-string-replace@^0.4.1: dependencies: lodash "^4.17.4" -react-syntax-highlighter@^12.2.1: - version "12.2.1" - resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e" - integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA== +react-syntax-highlighter@^13.5.0: + version "13.5.3" + resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz#9712850f883a3e19eb858cf93fad7bb357eea9c6" + integrity sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg== dependencies: "@babel/runtime" "^7.3.1" - highlight.js "~9.15.1" - lowlight "1.12.1" - prismjs "^1.8.4" - refractor "^2.4.1" + highlight.js "^10.1.1" + lowlight "^1.14.0" + prismjs "^1.21.0" + refractor "^3.1.0" react-syntax-highlighter@^13.5.1: version "13.5.1" @@ -21120,7 +21036,7 @@ react-wait@^0.3.0: resolved "https://registry.npmjs.org/react-wait/-/react-wait-0.3.0.tgz#0cdd4d919012451a5bc3ab0a16d00c6fd9a8c10b" integrity sha512-kB5x/kMKWcn0uVr9gBdNz21/oGbQwEQnF3P9p6E9yLfJ9DRcKS0fagbgYMFI0YFOoyKDj+2q6Rwax0kTYJF37g== -react@^16.0.0, react@^16.12.0, react@^16.13.1, react@^16.8.3, react@^16.9.17: +react@^16.0.0, 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== @@ -21315,16 +21231,6 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -recast@^0.14.7: - version "0.14.7" - resolved "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" - integrity sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A== - dependencies: - ast-types "0.11.3" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - recharts-scale@^0.4.2: version "0.4.3" resolved "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.3.tgz#040b4f638ed687a530357292ecac880578384b59" @@ -21433,15 +21339,6 @@ reflect-metadata@^0.1.13: resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -refractor@^2.4.1: - version "2.10.1" - resolved "https://registry.npmjs.org/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" - integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw== - dependencies: - hastscript "^5.0.0" - parse-entities "^1.1.2" - prismjs "~1.17.0" - refractor@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/refractor/-/refractor-3.1.0.tgz#b05a43c8a1b4fccb30001ffcbd5cd781f7f06f78" @@ -21482,6 +21379,11 @@ regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0 resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== +regenerator-runtime@^0.13.7: + version "0.13.7" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + regenerator-transform@^0.14.2: version "0.14.4" resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" @@ -21970,9 +21872,9 @@ rollup-plugin-esbuild@2.6.x: strip-json-comments "^3.1.1" rollup-plugin-peer-deps-external@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.3.tgz#059a8aec1eefb48a475e9fcedc3b9e3deb521213" - integrity sha512-W6IePXTExGXVDAlfZbNUUrx3GxUOZP248u5n4a4ID1XZMrbQ+uGeNiEfapvdzwx0qZi5DNH/hDLiPUP+pzFIxg== + version "2.2.4" + resolved "https://registry.npmjs.org/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.4.tgz#8a420bbfd6dccc30aeb68c9bf57011f2f109570d" + integrity sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g== rollup-plugin-postcss@^3.1.1: version "3.1.8" @@ -22405,7 +22307,7 @@ shell-quote@1.7.2: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== -shelljs@^0.8.2, shelljs@^0.8.3, shelljs@^0.8.4: +shelljs@^0.8.2, shelljs@^0.8.4: version "0.8.4" resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== @@ -22966,7 +22868,7 @@ store2@^2.7.1: resolved "https://registry.npmjs.org/store2/-/store2-2.10.0.tgz#46b82bb91878daf1b0d56dec2f1d41e54d5103cf" integrity sha512-tWEpK0snS2RPUq1i3R6OahfJNjWCQYNxq0+by1amCSuw0mXtymJpzmZIeYpA1UAa+7B0grCpNYIbDcd7AgTbFg== -storybook-dark-mode@^1.0.2: +storybook-dark-mode@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-1.0.3.tgz#8d58a874b6107ff1a7f29ebb0e6726b8036eee08" integrity sha512-mjHLrv/dwtqKmbOoQ2CMtGKDttWSnUybutujsIPxLcEC77EujjWiRBFv46LtXAZEyZLm8sGFUz0s6HJJfJ3tSw== @@ -23601,18 +23503,7 @@ tar-stream@^1.1.2: to-buffer "^1.1.1" xtend "^4.0.0" -tar-stream@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz#6d5ef1a7e5783a95ff70b69b97455a5968dc1325" - integrity sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q== - dependencies: - bl "^4.0.1" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar-stream@^2.1.4: +tar-stream@^2.0.0, tar-stream@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw== @@ -24106,10 +23997,10 @@ tryer@^1.0.1: resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -ts-dedent@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ts-dedent/-/ts-dedent-1.1.1.tgz#68fad040d7dbd53a90f545b450702340e17d18f3" - integrity sha512-UGTRZu1evMw4uTPyYF66/KFd22XiU+jMaIuHrkIHQ2GivAXVlLV0v/vHrpOuTRf9BmpNHi/SO7Vd0rLu0y57jg== +ts-dedent@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.0.0.tgz#47c5eb23d9096f3237cc413bc82d387d36dbe690" + integrity sha512-DfxKjSFQfw9+uf7N9Cy8Ebx9fv5fquK4hZ6SD3Rzr+1jKP6AVA6H8+B5457ZpUs0JKsGpGqIevbpZ9DMQJDp1A== ts-easing@^0.2.0: version "0.2.0" @@ -24213,6 +24104,11 @@ tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^2.0.1: + version "2.0.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" + integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -24325,11 +24221,6 @@ typed-rest-client@^1.7.3: tunnel "0.0.6" underscore "1.8.3" -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -24343,20 +24234,20 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript-json-schema@^0.45.0: - version "0.45.0" - resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.45.0.tgz#2f244e99518e589a442ee5f9c1d2c85a1ec7dc84" - integrity sha512-4MeX0HIODRd+K1/sIbkPryGXG43PVQ9cvIC8gDYml6yBgcsWLjvPMpTNr9VV+bQwpDLncB8Ie4qSenuKUwNZpg== + version "0.45.1" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.45.1.tgz#d3c1feea85b3bfeaf7e42a8c3bab80f2dc121a5d" + integrity sha512-Iz1NKVtJi09iZSzXj3J350GekBrZ1TiNw6Cbf42jLOGyooh9BWoi8XP6XlTIMOI3aMD8XxuL9hEvIEq8FD/WUw== dependencies: "@types/json-schema" "^7.0.6" glob "^7.1.6" json-stable-stringify "^1.0.1" - typescript "^4.1.2" - yargs "^16.1.1" + typescript "^4.1.3" + yargs "^16.2.0" -typescript@^4.0.3, typescript@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9" - integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== +typescript@^4.0.3, typescript@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== ua-parser-js@^0.7.18: version "0.7.21" @@ -25065,6 +24956,11 @@ webpack-dev-server@^3.11.0: ws "^6.2.1" yargs "^13.3.2" +webpack-filter-warnings-plugin@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz#dc61521cf4f9b4a336fbc89108a75ae1da951cdb" + integrity sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg== + webpack-hot-middleware@^2.25.0: version "2.25.0" resolved "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.0.tgz#4528a0a63ec37f8f8ef565cf9e534d57d09fe706" @@ -25075,16 +24971,6 @@ webpack-hot-middleware@^2.25.0: querystring "^0.2.0" strip-ansi "^3.0.0" -webpack-log@^1.1.2: - version "1.2.0" - resolved "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" - integrity sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA== - dependencies: - chalk "^2.1.0" - log-symbols "^2.1.0" - loglevelnext "^1.0.1" - uuid "^3.1.0" - webpack-log@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" @@ -25113,10 +24999,10 @@ webpack-virtual-modules@^0.2.2: dependencies: debug "^3.0.0" -webpack@^4.41.6, webpack@^4.43.0: - version "4.44.1" - resolved "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz#17e69fff9f321b8f117d1fda714edfc0b939cc21" - integrity sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ== +webpack@^4.41.6, webpack@^4.44.2: + version "4.44.2" + resolved "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" + integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== dependencies: "@webassemblyjs/ast" "1.9.0" "@webassemblyjs/helper-module-context" "1.9.0" @@ -25701,10 +25587,10 @@ yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.3, yargs@^16.1.1: - version "16.1.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz#5a4a095bd1ca806b0a50d0c03611d38034d219a1" - integrity sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w== +yargs@^16.0.3, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" escalade "^3.1.1" @@ -25796,13 +25682,13 @@ zenscroll@^4.0.2: resolved "https://registry.npmjs.org/zenscroll/-/zenscroll-4.0.2.tgz#e8d5774d1c0738a47bcfa8729f3712e2deddeb25" integrity sha1-6NV3TRwHOKR7z6hynzcS4t7d6yU= -zip-stream@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.2.tgz#3a20f1bd7729c2b59fd4efa04df5eb7a5a217d2e" - integrity sha512-TGxB2g+1ur6MHkvM644DuZr8Uzyz0k0OYWtS3YlpfWBEmK4woaC2t3+pozEL3dBfIPmpgmClR5B2QRcMgGt22g== +zip-stream@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.4.tgz#3a8f100b73afaa7d1ae9338d910b321dec77ff3a" + integrity sha512-a65wQ3h5gcQ/nQGWV1mSZCEzCML6EK/vyVPcrPNynySP1j3VBbQKh3nhC8CbORb+jfl2vXvh56Ul5odP1bAHqw== dependencies: archiver-utils "^2.1.0" - compress-commons "^4.0.0" + compress-commons "^4.0.2" readable-stream "^3.6.0" zombie@^6.1.4: