diff --git a/.changeset/dry-scissors-dream.md b/.changeset/dry-scissors-dream.md new file mode 100644 index 0000000000..09965f0f59 --- /dev/null +++ b/.changeset/dry-scissors-dream.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': minor +--- + +added the possibility to handle raw Gitlab URLs with nested namespaces diff --git a/.changeset/fresh-beans-call.md b/.changeset/fresh-beans-call.md new file mode 100644 index 0000000000..7327f9a3c9 --- /dev/null +++ b/.changeset/fresh-beans-call.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Add ability to customize `Read More` destination with `readMoreUrl` prop for `MissingAnnotationEmptyState` component. diff --git a/.changeset/good-beans-knock.md b/.changeset/good-beans-knock.md new file mode 100644 index 0000000000..91de53c128 --- /dev/null +++ b/.changeset/good-beans-knock.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Don't set the background color on an Avatar component that has a picture. diff --git a/.changeset/lucky-masks-talk.md b/.changeset/lucky-masks-talk.md new file mode 100644 index 0000000000..e15bfafcc2 --- /dev/null +++ b/.changeset/lucky-masks-talk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +Improved inline/type documentation for the addon. diff --git a/.changeset/nervous-bears-brush.md b/.changeset/nervous-bears-brush.md new file mode 100644 index 0000000000..f3b0c7db78 --- /dev/null +++ b/.changeset/nervous-bears-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +The Auth0 adapter no longer disables session refreshing. diff --git a/.changeset/olive-eggs-accept.md b/.changeset/olive-eggs-accept.md new file mode 100644 index 0000000000..66d44d9c3e --- /dev/null +++ b/.changeset/olive-eggs-accept.md @@ -0,0 +1,16 @@ +--- +'@backstage/backend-common': patch +--- + +**DEPRECATION**: Server-to-server authentication tokens issued from a +`TokenManager` (specifically, `ServerTokenManager`) now has an expiry time set, +for one hour in the future from when issued. This improves security. The ability +to pass in and validate tokens that either have a missing `exp` claim, or an +`exp` claim that expired in the past, is now deprecated. Trying to do so will +lead to logged warnings, and in a future release will instead lead to errors. + +It was always the case that users of this interface were expected to call its +`getToken()` method for every outgoing call and never hold on to any given token +for reuse. But this now has become even more important advice to heed, and you +should verify that you do not hold on to and reuse tokens such as these in your +own code. diff --git a/.changeset/pre.json b/.changeset/pre.json index e57d86a249..dff929aeec 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.70", @@ -185,11 +185,13 @@ "fair-pigs-mate", "fast-stingrays-guess", "fluffy-poems-sell", + "fluffy-sloths-deliver", "fresh-panthers-arrive", "funny-lamps-turn", "fuzzy-seahorses-teach", "gentle-penguins-kick", "giant-cheetahs-thank", + "good-beans-knock", "grumpy-panthers-peel", "hip-adults-collect", "hip-monkeys-hide", @@ -227,6 +229,7 @@ "renovate-759d9d5", "renovate-9466904", "renovate-abcbd6e", + "renovate-abcbd6e2", "renovate-b063c4b", "renovate-bf43c44", "renovate-bf63f74", @@ -237,7 +240,9 @@ "search-the-worst-of-you", "serious-apricots-collect", "seven-deers-rule", + "seven-panthers-pump", "shiny-apes-design", + "shiny-moles-study", "shiny-students-approve", "short-chicken-act", "short-dodos-sparkle", @@ -249,6 +254,7 @@ "smart-ghosts-search", "spotty-plums-rule", "stale-pigs-reply", + "stale-pugs-kiss", "strong-mangos-sell", "swift-bugs-share", "swift-parrots-hammer", @@ -275,6 +281,7 @@ "wicked-vans-press", "wild-pigs-work", "wise-countries-watch", + "wise-doors-hammer", "wise-emus-wait", "witty-lions-reply" ] diff --git a/.changeset/pretty-hornets-listen.md b/.changeset/pretty-hornets-listen.md new file mode 100644 index 0000000000..6e0701e617 --- /dev/null +++ b/.changeset/pretty-hornets-listen.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': patch +--- + +Fix issue where `nextPageCursor` is defined on the last page of results diff --git a/.changeset/real-lions-crash.md b/.changeset/real-lions-crash.md new file mode 100644 index 0000000000..f3087a1bc0 --- /dev/null +++ b/.changeset/real-lions-crash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Update the rendering of links in the entity inspector so that values starting with `https?://` are rendered as links as well. diff --git a/.changeset/renovate-9008399.md b/.changeset/renovate-9008399.md new file mode 100644 index 0000000000..64e1dd07a8 --- /dev/null +++ b/.changeset/renovate-9008399.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-codescene': patch +--- + +Updated dependency `@testing-library/user-event` to `^14.0.0`. diff --git a/.changeset/renovate-abcbd6e.md b/.changeset/renovate-abcbd6e.md deleted file mode 100644 index e96d9ea875..0000000000 --- a/.changeset/renovate-abcbd6e.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-techdocs': patch ---- - -Updated dependency `event-source-polyfill` to `1.0.26`. diff --git a/.changeset/renovate-db1641c.md b/.changeset/renovate-db1641c.md new file mode 100644 index 0000000000..8d34bd3eb1 --- /dev/null +++ b/.changeset/renovate-db1641c.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-codescene': patch +'@backstage/plugin-sonarqube': patch +--- + +Updated dependency `rc-progress` to `3.3.2`. diff --git a/.changeset/short-ears-sit.md b/.changeset/short-ears-sit.md new file mode 100644 index 0000000000..e75908a37d --- /dev/null +++ b/.changeset/short-ears-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +Fix kind filter error in the dev app diff --git a/.changeset/shy-rings-mix.md b/.changeset/shy-rings-mix.md new file mode 100644 index 0000000000..de322fdf85 --- /dev/null +++ b/.changeset/shy-rings-mix.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Fix SAML session schema to no longer require the (deprecated) id, to unbreak session data storage. diff --git a/.changeset/sixty-bulldogs-hang.md b/.changeset/sixty-bulldogs-hang.md new file mode 100644 index 0000000000..61367aad08 --- /dev/null +++ b/.changeset/sixty-bulldogs-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Add controls to Storybook stories diff --git a/.changeset/spotty-papayas-shave.md b/.changeset/spotty-papayas-shave.md new file mode 100644 index 0000000000..5a741b6b33 --- /dev/null +++ b/.changeset/spotty-papayas-shave.md @@ -0,0 +1,37 @@ +--- +'@backstage/create-app': patch +--- + +Integrates TechDocs add-ons with the app package so add-ons are configured when creating an app using the Backstage CLI. To apply these changes to an existing application do the following: + +1. Add the `@backstage/plugin-techdocs-react` and `@backstage/plugin-techdocs-module-addons-contrib` packages to your app's dependencies; +2. And then register the `` Addon in your `packages/app/src/App.tsx` file, there where you define a route to ``: + +```diff +import { + DefaultTechDocsHome, + TechDocsIndexPage, + TechDocsReaderPage, +} from '@backstage/plugin-techdocs'; ++ import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; ++ import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; + +// ... + +const AppRoutes = () => { + + // ... other plugin routes + }> + + + } + > ++ ++ ++ + + ; +}; +``` diff --git a/.changeset/sweet-icons-sneeze.md b/.changeset/sweet-icons-sneeze.md new file mode 100644 index 0000000000..b12424c7a8 --- /dev/null +++ b/.changeset/sweet-icons-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fix `EntityTypeFilter` so generating available types is case insensitive diff --git a/.changeset/tall-tables-smash.md b/.changeset/tall-tables-smash.md new file mode 100644 index 0000000000..2bf277879e --- /dev/null +++ b/.changeset/tall-tables-smash.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-graphiql': patch +'@backstage/plugin-api-docs': patch +--- + +Add the dependency `graphql-ws` to fix the latest release of `@graphiql/toolkit` that has a missing dependency diff --git a/.changeset/techdocs-bob-law-blog.md b/.changeset/techdocs-bob-law-blog.md new file mode 100644 index 0000000000..581ab19bec --- /dev/null +++ b/.changeset/techdocs-bob-law-blog.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-techdocs-react': major +'@backstage/plugin-techdocs-addons-test-utils': major +'@backstage/plugin-techdocs-module-addons-contrib': major +--- + +The TechDocs Addon framework is now generally available. diff --git a/.changeset/techdocs-khaki-cheetahs-clap.md b/.changeset/techdocs-khaki-cheetahs-clap.md new file mode 100644 index 0000000000..5aba436534 --- /dev/null +++ b/.changeset/techdocs-khaki-cheetahs-clap.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-react': patch +--- + +Added overload signatures for `createTechDocsAddonExtension` to handle TechDocs addons without props. diff --git a/.changeset/techdocs-light-treason.md b/.changeset/techdocs-light-treason.md new file mode 100644 index 0000000000..52136a732d --- /dev/null +++ b/.changeset/techdocs-light-treason.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Updated the default version of the `@spotify/techdocs` container used when `techdocs.generator.runIn` is `docker` to `v1.0.3`. diff --git a/.changeset/techdocs-seal-deal.md b/.changeset/techdocs-seal-deal.md new file mode 100644 index 0000000000..865d1fc837 --- /dev/null +++ b/.changeset/techdocs-seal-deal.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Fixed a bug that could cause TechDocs index generation to hang and fail when an underlying TechDocs site's `search_index.json` was empty. diff --git a/.changeset/techdocs-steve-holt.md b/.changeset/techdocs-steve-holt.md new file mode 100644 index 0000000000..c456d48cf8 --- /dev/null +++ b/.changeset/techdocs-steve-holt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Hidden exports related to experimental TechDocs reader functionality have been removed and can no longer be imported. In the unlikely event you were using these exports, you can now take advantage of the officially supported and generally available TechDocs Addon framework instead. diff --git a/.changeset/techdocs-stupid-radios-approve.md b/.changeset/techdocs-stupid-radios-approve.md new file mode 100644 index 0000000000..813e895611 --- /dev/null +++ b/.changeset/techdocs-stupid-radios-approve.md @@ -0,0 +1,5 @@ +--- +'@techdocs/cli': patch +--- + +Update `techdocs-cli serve`'s `proxyEndpoint` to match the base URL of the embedded techdocs app. diff --git a/.changeset/techdocs-weak-boats-work.md b/.changeset/techdocs-weak-boats-work.md new file mode 100644 index 0000000000..ec4f089592 --- /dev/null +++ b/.changeset/techdocs-weak-boats-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +Introducing the Expandable Navigation addon, which lets you expand and collapse the TechDocs main navigation and store your preference in local storage. diff --git a/.changeset/techdocs-wee-britain.md b/.changeset/techdocs-wee-britain.md new file mode 100644 index 0000000000..661ff76fc5 --- /dev/null +++ b/.changeset/techdocs-wee-britain.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-addons-test-utils': patch +--- + +Fixed a type bug preventing `buildAddonsInTechDocs().withApis()` from being called with multiple partial API implementations. diff --git a/.changeset/tough-queens-hope.md b/.changeset/tough-queens-hope.md new file mode 100644 index 0000000000..6816893611 --- /dev/null +++ b/.changeset/tough-queens-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Added a chevron Indicator when the sidebar is collapsed and has a sub-menu diff --git a/.changeset/unlucky-bobcats-fold.md b/.changeset/unlucky-bobcats-fold.md new file mode 100644 index 0000000000..6dd820db8d --- /dev/null +++ b/.changeset/unlucky-bobcats-fold.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': minor +--- + +Removed the explicit `disableRefresh` option from `OAuthAdapter`. Refresh can still be disabled for a provider by not implementing the `refresh` method. diff --git a/.github/renovate.json5 b/.github/renovate.json5 index ff351a5e0f..a8bc3448a5 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -3,7 +3,7 @@ extends: ['config:base', ':disableDependencyDashboard', ':gitSignOff'], rangeStrategy: 'update-lockfile', // @elastic/elasticsearch is ignored due to licensing issues. See #10992 - ignoreDeps: ['@elastic/elasticsearch'], + ignoreDeps: ['@elastic/elasticsearch', 'event-source-polyfill'], packageRules: [ { matchSourceUrlPrefixes: ['https://github.com/spotify/web-scripts'], diff --git a/.github/workflows/verify_dco.yaml b/.github/workflows/verify_dco.yaml index 71bd322eca..2094327d23 100644 --- a/.github/workflows/verify_dco.yaml +++ b/.github/workflows/verify_dco.yaml @@ -54,7 +54,7 @@ jobs: console.log(`creating comment on PR #${pull.number}`); const body = ` Thanks for the contribution! - All commits need to be DCO signed before merging. Please refer to the the [DCO section in CONTRIBUTING.md](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) or the [DCO](${checks.data.check_runs[0].html_url}) status for more info. + All commits need to be DCO signed before they are reviewed. Please refer to the the [DCO section in CONTRIBUTING.md](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) or the [DCO](${checks.data.check_runs[0].html_url}) status for more info. `; await github.rest.issues.createComment({ repo, diff --git a/ADOPTERS.md b/ADOPTERS.md index b163a5c612..3915aee949 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -125,3 +125,5 @@ _If you're using Backstage in your organization, please try to add your company | [Back Market](https://www.backmarket.com) | [Sami Farhat](https://github.com/skfarhat) | Internal Developer Portal featuring catalog, tech-radar, ownership management, component creation (scaffolder) and centralized infrastructure management -- probably more to come. | | [Avalia Systems](https://avalia.io) | [Olivier Liechti](https://github.com/wasadigi), [Fabio Velloso](https://github.com/fabiovelloso) | Innersource, software analytics, knowledge base for 360 software assessments, collaborative applications, hub for tracking and sharing IP assets. | | [Albert Heijn](https://ah.technology) | [Joost Hofman](https://github.com/joosthofman), [Reindrich Geerman](https://github.com/reinst) | Single point of entry for all our engineers (Developer portal), Tech radar, catalog, templates (paved roads) and tech documentation. | +| [Wise, formerly TransferWise](https://wise.com) | [Andrew Beveridge](https://github.com/beveradb) | It's early days for us, we're trying to start small with catalog, tech docs and unified search. Future ambitious vision includes scaffolder for one-click component addition, building out integrations with CI/CD tooling, kubernetes clusters, monitoring/alerting tooling etc. and aiming for a frictionless "golden path" for engineers! 🚀 | + diff --git a/cypress/src/integration/plugins/techdocs.spec.ts b/cypress/src/integration/plugins/techdocs.spec.ts index d6049ea53d..1e69ba46ad 100644 --- a/cypress/src/integration/plugins/techdocs.spec.ts +++ b/cypress/src/integration/plugins/techdocs.spec.ts @@ -38,6 +38,7 @@ describe('TechDocs', () => { it('should navigate to the TechDocs home page from the URL', () => { cy.visit('/docs'); + cy.wait(500); cy.contains('Documentation'); @@ -45,15 +46,12 @@ describe('TechDocs', () => { it('should navigate to a specific TechDocs entity from the "Overview" tab', () => { cy.visit('/docs'); - cy.contains('techdocs-e2e-fixture') - .parents() - .eq(2) - .contains('Read Docs') - .click(); + + cy.contains('techdocs-e2e-fixture').click(); cy.location().should(loc => { expect(loc.pathname).to.eq( - '/docs/default/Component/techdocs-e2e-fixture', + '/docs/default/component/techdocs-e2e-fixture', ); }); }); @@ -84,7 +82,6 @@ describe('TechDocs', () => { cy.visit( '/docs/default/Component/techdocs-e2e-fixture/sub-page-two#section-23', ); - cy.waitSectionTwoPage(); // This is used to test the post-render behavior of the techdocs Reader cy.wait(500); @@ -101,10 +98,43 @@ describe('TechDocs', () => { }); }); + describe('Rendering TechDocs Addons', () => { + it('should render a content addon', () => { + cy.visit('/docs/default/Component/techdocs-e2e-fixture'); + + cy.contains('e2e Fixture Documentation'); + + // highlight a snippet of text + cy.getTechDocsShadowRoot() + .find('article > p') + .then($el => { + const el = $el[0]; + const document = el.ownerDocument; + const range = document.createRange(); + range.selectNodeContents(el); + document?.getSelection()?.removeAllRanges(); + document?.getSelection()?.addRange(range); + }); + + cy.document().trigger('selectionchange'); + + // wait for new issue default debounce time + cy.wait(600); + + // assert that the new issue button has a right url + cy.getTechDocsShadowRoot() + .contains('Open new Github issue') + .should( + 'have.attr', + 'href', + 'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fdocs%2Fdefault%2FComponent%2Ftechdocs-e2e-fixture%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Findex.md%3E', + ); + }); + }); + describe('Navigating within TechDocs', () => { it('should navigate to a specific TechDocs page via the navigation bar', () => { cy.visit('/docs/default/Component/techdocs-e2e-fixture'); - cy.waitHomePage(); cy.getTechDocsShadowRoot().within(() => { cy.getTechDocsNavigation() @@ -118,14 +148,18 @@ describe('TechDocs', () => { describe('Navigating within a TechDocs page', () => { beforeEach(() => { cy.visit('/docs/default/Component/techdocs-e2e-fixture/sub-page-two'); - cy.waitSectionTwoPage(); }); + it('should navigate to a specific fragment within the page via the table of contents - Level 1', () => { return cy.getTechDocsShadowRoot().within(() => { // Section 3 - cy.getTechDocsTableOfContents().within(() => { - cy.get('> div > div > nav > ul > li:nth-child(3) > a').click(); - }); + cy.getTechDocsTableOfContents() + .find('a') + .contains('Section 2.3') + .click(); + + // wait scroll timeout + cy.wait(500); cy.isInViewport('#section-23'); }); @@ -136,20 +170,20 @@ describe('TechDocs', () => { cy.isNotInViewport('#sub-section-222'); // Section 2.2 cy.getTechDocsTableOfContents() - .find( - '> div > div > nav > ul > li:nth-child(2) > nav > ul > li:nth-child(2) > a', - ) + .find('a') + .contains('Section 2.2.2') .click(); + // wait scroll timeout + cy.wait(500); + cy.isInViewport('#sub-section-222'); }); }); it('should navigate to a specific TechDocs page fragment from a link', () => { return cy.getTechDocsShadowRoot().within(() => { - cy.get('.md-content > article') - .contains('Link to Section 1.1') - .click(); + cy.get('article').contains('Link to Section 1.1').click(); cy.location().should(loc => { expect(loc.pathname).to.eq( @@ -162,7 +196,7 @@ describe('TechDocs', () => { it('should navigate to the next page within a TechDocs entity', () => { return cy.getTechDocsShadowRoot().within(() => { - cy.get('.md-footer-nav__link--next').click(); + cy.get('footer a').contains('Sub-page 3').click(); cy.location().should(loc => { expect(loc.pathname).to.eq( @@ -174,7 +208,7 @@ describe('TechDocs', () => { it('should navigate to the previous page within a TechDocs entity', () => { return cy.getTechDocsShadowRoot().within(() => { - cy.get('.md-footer-nav__link--prev').click(); + cy.get('footer a').contains('Sub-page 1').click(); cy.location().should(loc => { expect(loc.pathname).to.eq( diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts index 666dc157d7..9973afb6a7 100644 --- a/cypress/src/support/commands.ts +++ b/cypress/src/support/commands.ts @@ -25,7 +25,7 @@ Cypress.Commands.add('loginAsGuest', () => { }); Cypress.Commands.add('getTechDocsShadowRoot', () => { - cy.get('[data-testid="techdocs-content-shadowroot"]').shadow(); + cy.get('[data-testid="techdocs-native-shadowroot"]').shadow(); }); Cypress.Commands.add('isNotInViewport', element => { @@ -57,11 +57,11 @@ Cypress.Commands.add('isInViewport', element => { }); Cypress.Commands.add('getTechDocsTableOfContents', () => { - cy.get('[data-md-component="toc"]'); + cy.get('[data-md-type="toc"]'); }); Cypress.Commands.add('getTechDocsNavigation', () => { - cy.get('[data-md-component="navigation"]'); + cy.get('[data-md-type="navigation"]'); }); Cypress.Commands.add('mockSockJSNode', () => { diff --git a/docs/assets/techdocs/report-issue-addon.png b/docs/assets/techdocs/report-issue-addon.png new file mode 100644 index 0000000000..4c61935f2f Binary files /dev/null and b/docs/assets/techdocs/report-issue-addon.png differ diff --git a/docs/assets/techdocs/report-issue-template.png b/docs/assets/techdocs/report-issue-template.png new file mode 100644 index 0000000000..35dca05e1f Binary files /dev/null and b/docs/assets/techdocs/report-issue-template.png differ diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index 282088fef9..bd2bcd1694 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -153,7 +153,6 @@ export const createOktaProvider: AuthProviderFactory = ({ // Wrap the OAuthProviderHandlers with OAuthProvider, which implements AuthProviderRouteHandlers return OAuthProvider.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, tokenIssuer, }); diff --git a/docs/features/techdocs/addons.md b/docs/features/techdocs/addons.md index e8af56d3fc..5305e3bc68 100644 --- a/docs/features/techdocs/addons.md +++ b/docs/features/techdocs/addons.md @@ -111,10 +111,11 @@ page header, TechDocs Addons whose location is `Header` will not be rendered. Addons can, in principle, be provided by any plugin! To make it easier to discover available Addons, we've compiled a list of them here: -| Addon | Package/Plugin | Description | -| ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [``](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.reportissue) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to select a portion of text on a TechDocs page and open an issue against the repository that contains the documentation, populating the issue description with the selected text according to a configurable template. | -| [``](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.textsize) | `@backstage/plugin-techdocs-module-addons-contrib` | This TechDocs addon allows users to customize text size on documentation pages, they can select how much they want to increase or decrease the font size via slider or buttons. The default value for font size is 100% and this setting is kept in the browser's local storage whenever it is changed. | +| Addon | Package/Plugin | Description | +| ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [``](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.expandablenavigation) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to expand or collapse the entire TechDocs main navigation, and keeps the user's preferred state between documentation sites. | +| [``](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.reportissue) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to select a portion of text on a TechDocs page and open an issue against the repository that contains the documentation, populating the issue description with the selected text according to a configurable template. | +| [``](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.textsize) | `@backstage/plugin-techdocs-module-addons-contrib` | This TechDocs addon allows users to customize text size on documentation pages, they can select how much they want to increase or decrease the font size via slider or buttons. The default value for font size is 100% and this setting is kept in the browser's local storage whenever it is changed. | Got an Addon to contribute? Feel free to add a row above! diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 9a7dccd5a6..52c389975e 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -120,7 +120,7 @@ Generate TechDocs documentation site using MkDocs. Options: --source-dir Source directory containing mkdocs.yml and docs/ directory. (default: ".") --output-dir Output directory containing generated TechDocs site. (default: "./site/") - --docker-image The mkdocs docker container to use (default: "spotify/techdocs:v1.0.2") + --docker-image The mkdocs docker container to use (default: "spotify/techdocs:v1.0.3") --no-pull Do not pull the latest docker image --no-docker Do not use Docker, use MkDocs executable and plugins in current user environment. --techdocs-ref The repository hosting documentation source files e.g. diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 1eeebae903..f8bf98c0e0 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -54,8 +54,48 @@ const AppRoutes = () => { }; ``` -That's it! But now, we need the TechDocs Backend plugin for the frontend to -work. +It would be nice to decorate your pages with something else... Having a link that redirects you to a new issue page when you highlight text in your documentation would be really cool, right? Let's learn how to do this using the TechDocs Addon Framework! + +With the [TechDocs Addon framework](https://backstage.io/docs/features/techdocs/addons#installing-and-using-addons), you can render React components in documentation pages and these Addons can be provided by any Backstage plugin. The framework is exported by the [@backstage/plugin-techdocs-react](https://www.npmjs.com/package/@backstage/plugin-techdocs-react) package and there is a `` Addon in the [@backstage/plugin-techdocs-module-addons-contrib](https://www.npmjs.com/package/@backstage/plugin-techdocs-module-addons-contrib) package for you to use once you have these two dependencies installed: + +```diff +import { + DefaultTechDocsHome, + TechDocsIndexPage, + TechDocsReaderPage, +} from '@backstage/plugin-techdocs'; ++ import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; ++ import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; + +// ... + +const AppRoutes = () => { + + // ... other plugin routes + }> + + + } + > ++ ++ ++ + + ; +}; +``` + +I know, you're curious to see how it looks, aren't you? See the image below: + +TechDocs Report Issue Add-on + +By clicking the open new issue button, you will be redirected to the new issue page according to the source code provider you are using: + +TechDocs Report Issue Template + +That's it! Now, we need the TechDocs Backend plugin for the frontend to work. ## Adding TechDocs Backend plugin diff --git a/docs/releases/v1.2.0-next.3-changelog.md b/docs/releases/v1.2.0-next.3-changelog.md new file mode 100644 index 0000000000..4efce476d4 --- /dev/null +++ b/docs/releases/v1.2.0-next.3-changelog.md @@ -0,0 +1,73 @@ +# Release v1.2.0-next.3 + +## @backstage/core-components@0.9.4-next.2 + +### Patch Changes + +- 52c02ac02b: Don't set the background color on an Avatar component that has a picture. +- 3603014e0e: Add ARIA landmark(
), & label and a heading to OAuthRequestDialog. Removed nested interactive control (button). +- 2025d7c123: Properly highlight `SidebarSubmenuItem` dropdown items on hover, use ellipsis styling on long labels in `SidebarSubmenu`, allow `icon` and `to` properties to be optional on `SidebarSubmenuItem`, and fix `SidebarPage` padding to be responsive to pinned state + +## @backstage/plugin-home@0.4.21-next.3 + +### Patch Changes + +- 69093c5f91: Display entity titles in `StarredEntities` home page card (if defined) and don't show entities which no longer exist +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + +## @backstage/plugin-kubernetes@0.6.5-next.3 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.2.10-next.1 + - @backstage/core-components@0.9.4-next.2 + +## @backstage/plugin-kubernetes-backend@0.5.1-next.2 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.2.10-next.1 + +## @backstage/plugin-kubernetes-common@0.2.10-next.1 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. + +## @backstage/plugin-org@0.5.5-next.3 + +### Patch Changes + +- 2025d7c123: Include namespace in `MyGroupSidebarItem` if not default and remove root item routing if there are multiple groups +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + +## @backstage/plugin-scaffolder@1.2.0-next.3 + +### Patch Changes + +- cc8ddd0979: revert dependency `event-source-polyfill` to `1.0.25` +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + +## @backstage/plugin-techdocs@1.1.1-next.3 + +### Patch Changes + +- cc8ddd0979: revert dependency `event-source-polyfill` to `1.0.25` +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 diff --git a/microsite/data/on-demand/20220420-1.yaml b/microsite/data/on-demand/20220420-1.yaml index 6089ac1cc9..96560ec436 100644 --- a/microsite/data/on-demand/20220420-1.yaml +++ b/microsite/data/on-demand/20220420-1.yaml @@ -1,7 +1,7 @@ --- title: Adopters Community Sessions date: April 20, 2022 -category: Upcoming +category: Meetup description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. youtubeUrl: https://youtu.be/mFi_X58igzk youtubeImgUrl: https://backstage.io/img/b-sessions.png diff --git a/microsite/data/on-demand/20220427-1.yaml b/microsite/data/on-demand/20220427-1.yaml index 451ee3bc67..80ec8eae00 100644 --- a/microsite/data/on-demand/20220427-1.yaml +++ b/microsite/data/on-demand/20220427-1.yaml @@ -1,7 +1,7 @@ --- title: Contributor Community Sessions date: April 27, 2022 -category: Upcoming +category: Meetup description: Join the maintainers and contributors for the Contributor Community Sessions youtubeUrl: https://youtu.be/evf_LV0KzIk youtubeImgUrl: https://backstage.io/img/b-sessions.png diff --git a/microsite/data/on-demand/20220518-01.yaml b/microsite/data/on-demand/20220518-01.yaml new file mode 100644 index 0000000000..e98c79005a --- /dev/null +++ b/microsite/data/on-demand/20220518-01.yaml @@ -0,0 +1,9 @@ +--- +title: Adopters Community Sessions +date: May 18, 2022 +category: Upcoming +description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. +youtubeUrl: https://youtu.be/dEd1fl3wRv +youtubeImgUrl: https://backstage.io/img/b-sessions.png +rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com +eventUrl: https://github.com/backstage/community/issues/46 diff --git a/microsite/data/plugins/kpt-config-as-data.yaml b/microsite/data/plugins/kpt-config-as-data.yaml new file mode 100644 index 0000000000..03d5d66947 --- /dev/null +++ b/microsite/data/plugins/kpt-config-as-data.yaml @@ -0,0 +1,9 @@ +--- +title: Configuration as Data +author: kpt +authorUrl: https://kpt.dev +category: Configuration +description: Configuration GUI over GitOps using kpt, with WYSIWYG editing, review and approval, versioning and undo, and package cloning and upgrades. +documentation: https://github.com/GoogleContainerTools/kpt-backstage-plugins/tree/main/plugins/cad +iconUrl: https://github.com/GoogleContainerTools/kpt/blob/main/logo/KptLogoSmall.png?raw=true +npmPackageName: '@kpt/backstage-plugin-cad' diff --git a/microsite/pages/en/live.js b/microsite/pages/en/live.js index 374b690d89..9f8a0e24b0 100644 --- a/microsite/pages/en/live.js +++ b/microsite/pages/en/live.js @@ -34,7 +34,7 @@ const Background = props => { diff --git a/package.json b/package.json index d415477294..c215ef69a4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.2.0-next.2", + "version": "1.2.0-next.3", "dependencies": { "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.17.11", @@ -68,7 +68,7 @@ "concurrently": "^7.0.0", "eslint-plugin-notice": "^0.9.10", "fs-extra": "10.1.0", - "husky": "^7.0.4", + "husky": "^8.0.0", "lerna": "^4.0.0", "lint-staged": "^12.2.0", "minimist": "^1.2.5", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 089900fb77..35c61f2f16 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -71,6 +71,7 @@ import { } from '@backstage/plugin-techdocs'; import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; import { + ExpandableNavigation, ReportIssue, TextSize, } from '@backstage/plugin-techdocs-module-addons-contrib'; @@ -185,6 +186,7 @@ const routes = ( > {techDocsPage} + diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 13c4ed62ce..6059e68792 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -617,18 +617,20 @@ export class ServerTokenManager implements TokenManager { // (undocumented) static fromConfig( config: Config, - options: { - logger: Logger; - }, + options: ServerTokenManagerOptions, ): ServerTokenManager; // (undocumented) getToken(): Promise<{ token: string; }>; - // (undocumented) static noop(): TokenManager; } +// @public +export interface ServerTokenManagerOptions { + logger: Logger; +} + // @public export type ServiceBuilder = { loadConfig(config: Config): ServiceBuilder; @@ -687,10 +689,8 @@ export interface StatusCheckHandlerOptions { // @public export interface TokenManager { - // (undocumented) - authenticate: (token: string) => Promise; - // (undocumented) - getToken: () => Promise<{ + authenticate(token: string): Promise; + getToken(): Promise<{ token: string; }>; } diff --git a/packages/backend-common/src/tokens/ServerTokenManager.test.ts b/packages/backend-common/src/tokens/ServerTokenManager.test.ts index 0ff7bfb316..6a72b99908 100644 --- a/packages/backend-common/src/tokens/ServerTokenManager.test.ts +++ b/packages/backend-common/src/tokens/ServerTokenManager.test.ts @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { getVoidLogger } from '../logging/voidLogger'; + import { ConfigReader } from '@backstage/config'; -import { ServerTokenManager } from './ServerTokenManager'; -import { Logger } from 'winston'; import * as jose from 'jose'; +import { Logger } from 'winston'; +import { getVoidLogger } from '../logging/voidLogger'; +import { ServerTokenManager } from './ServerTokenManager'; import { TokenManager } from './types'; const emptyConfig = new ConfigReader({}); @@ -35,6 +36,7 @@ describe('ServerTokenManager', () => { afterEach(() => { process.env = env; + jest.useRealTimers(); }); describe('getToken', () => { @@ -166,6 +168,42 @@ describe('ServerTokenManager', () => { /invalid server token/i, ); }); + + it('should throw for expired tokens, and re-issue new ones', async () => { + jest.useFakeTimers(); + const warn = jest.spyOn(logger, 'warn'); + + const tokenManager = ServerTokenManager.fromConfig(configWithSecret, { + logger, + }); + + const { token: token1 } = await tokenManager.getToken(); + await expect(tokenManager.authenticate(token1)).resolves.not.toThrow(); + expect(warn.mock.calls.length).toBe(0); + + // Right before the reissue timeout, it still returns the same token + jest.advanceTimersByTime(9 * 60 * 1000); + const { token: token1Again } = await tokenManager.getToken(); + expect(token1).toEqual(token1Again); + await expect(tokenManager.authenticate(token1)).resolves.not.toThrow(); + expect(warn.mock.calls.length).toBe(0); + + // Right after the reissue timeout, the old ones are still valid but returning a new token + jest.advanceTimersByTime(2 * 60 * 1000); + const { token: token2 } = await tokenManager.getToken(); + expect(token1).not.toEqual(token2); + await expect(tokenManager.authenticate(token1)).resolves.not.toThrow(); + await expect(tokenManager.authenticate(token2)).resolves.not.toThrow(); + expect(warn.mock.calls.length).toBe(0); + + // After expiry of the first one, it gets warnings but the newest one is still valid + jest.advanceTimersByTime(52 * 60 * 1000); + await expect(tokenManager.authenticate(token1)).resolves.not.toThrow(); + await expect(tokenManager.authenticate(token2)).resolves.not.toThrow(); + expect(warn.mock.calls[0][0]).toMatchInlineSnapshot( + '"#### DEPRECATION WARNING: #### Server-to-server token had an expired exp claim, support for this has been deprecated and will result in errors in a future release"', + ); + }); }); describe('fromConfig', () => { @@ -242,7 +280,7 @@ describe('ServerTokenManager', () => { }); }); - describe('ServerTokenManager.noop', () => { + describe('noop', () => { let noopTokenManager: TokenManager; beforeEach(() => { diff --git a/packages/backend-common/src/tokens/ServerTokenManager.ts b/packages/backend-common/src/tokens/ServerTokenManager.ts index 484b99ca4d..329c2f164c 100644 --- a/packages/backend-common/src/tokens/ServerTokenManager.ts +++ b/packages/backend-common/src/tokens/ServerTokenManager.ts @@ -14,12 +14,22 @@ * limitations under the License. */ -import { base64url, generateSecret, SignJWT, jwtVerify, exportJWK } from 'jose'; import { Config } from '@backstage/config'; -import { AuthenticationError } from '@backstage/errors'; -import { TokenManager } from './types'; +import { AuthenticationError, NotAllowedError } from '@backstage/errors'; +import { base64url, exportJWK, generateSecret, jwtVerify, SignJWT } from 'jose'; +import { DateTime, Duration } from 'luxon'; import { Logger } from 'winston'; +import { TokenManager } from './types'; +const TOKEN_ALG = 'HS256'; +const TOKEN_SUB = 'backstage-server'; +const TOKEN_EXPIRY_AFTER = Duration.fromObject({ hours: 1 }); +const TOKEN_REISSUE_AFTER = Duration.fromObject({ minutes: 10 }); + +/** + * A token manager that issues static dummy tokens and never fails + * authentication. This can be useful for testing. + */ class NoopTokenManager implements TokenManager { public readonly isInsecureServerTokenManager: boolean = true; @@ -30,6 +40,18 @@ class NoopTokenManager implements TokenManager { async authenticate() {} } +/** + * Options for {@link ServerTokenManager}. + * + * @public + */ +export interface ServerTokenManagerOptions { + /** + * The logger to use. + */ + logger: Logger; +} + /** * Creates and validates tokens for use during backend-to-backend * authentication. @@ -37,44 +59,51 @@ class NoopTokenManager implements TokenManager { * @public */ export class ServerTokenManager implements TokenManager { - private verificationKeys: Uint8Array[]; + private readonly options: ServerTokenManagerOptions; + private readonly verificationKeys: Uint8Array[]; private signingKey: Uint8Array; - private privateKeyPromise?: Promise; - private logger: Logger; + private privateKeyPromise: Promise | undefined; + private currentTokenPromise: Promise<{ token: string }> | undefined; + private warnedForMissingExpClaim = false; + private warnedForExpiredExpClaim = false; + /** + * Creates a token manager that issues static dummy tokens and never fails + * authentication. This can be useful for testing. + */ static noop(): TokenManager { return new NoopTokenManager(); } - static fromConfig(config: Config, options: { logger: Logger }) { - const { logger } = options; - + static fromConfig(config: Config, options: ServerTokenManagerOptions) { const keys = config.getOptionalConfigArray('backend.auth.keys'); if (keys?.length) { return new ServerTokenManager( keys.map(key => key.getString('secret')), - logger, + options, ); } + if (process.env.NODE_ENV !== 'development') { throw new Error( 'You must configure at least one key in backend.auth.keys for production.', ); } + // For development, if a secret has not been configured, we auto generate a secret instead of throwing. - logger.warn( + options.logger.warn( 'Generated a secret for backend-to-backend authentication: DEVELOPMENT USE ONLY.', ); - return new ServerTokenManager([], logger); + return new ServerTokenManager([], options); } - private constructor(secrets: string[], logger: Logger) { + private constructor(secrets: string[], options: ServerTokenManagerOptions) { if (!secrets.length && process.env.NODE_ENV !== 'development') { throw new Error( 'No secrets provided when constructing ServerTokenManager', ); } - this.logger = logger; + this.options = options; this.verificationKeys = secrets.map(s => base64url.decode(s)); this.signingKey = this.verificationKeys[0]; } @@ -86,11 +115,13 @@ export class ServerTokenManager implements TokenManager { 'Key generation is not supported outside of the dev environment', ); } + if (this.privateKeyPromise) { return this.privateKeyPromise; } + const promise = (async () => { - const secret = await generateSecret('HS256'); + const secret = await generateSecret(TOKEN_ALG); const jwk = await exportJWK(secret); this.verificationKeys.push(base64url.decode(jwk.k ?? '')); this.signingKey = this.verificationKeys[0]; @@ -98,13 +129,15 @@ export class ServerTokenManager implements TokenManager { })(); try { - // If we fail to generate a new key, we need to clear the state so that - // the next caller will try to generate another key. + this.privateKeyPromise = promise; await promise; } catch (error) { - this.logger.error(`Failed to generate new key, ${error}`); + // If we fail to generate a new key, we need to clear the state so that + // the next caller will try to generate another key. + this.options.logger.error(`Failed to generate new key, ${error}`); delete this.privateKeyPromise; } + return promise; } @@ -112,26 +145,83 @@ export class ServerTokenManager implements TokenManager { if (!this.verificationKeys.length) { await this.generateKeys(); } - const sub = 'backstage-server'; - const jwt = await new SignJWT({ alg: 'HS256' }) - .setProtectedHeader({ alg: 'HS256', sub: sub }) - .setSubject('backstage-server') - .sign(this.signingKey); - return { token: jwt }; + + if (this.currentTokenPromise) { + return this.currentTokenPromise; + } + + const result = Promise.resolve().then(async () => { + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: TOKEN_ALG }) + .setSubject(TOKEN_SUB) + .setExpirationTime( + DateTime.now().plus(TOKEN_EXPIRY_AFTER).toUnixInteger(), + ) + .sign(this.signingKey); + return { token: jwt }; + }); + + this.currentTokenPromise = result; + + result + .then(() => { + setTimeout(() => { + this.currentTokenPromise = undefined; + }, TOKEN_REISSUE_AFTER.toMillis()); + }) + .catch(() => { + this.currentTokenPromise = undefined; + }); + + return result; } async authenticate(token: string): Promise { let verifyError = undefined; + for (const key of this.verificationKeys) { try { - await jwtVerify(token, key); - // If the verify succeeded, return + const { + protectedHeader: { alg }, + payload: { sub, exp }, + } = await jwtVerify(token, key, { + // TODO(freben): Holding on to tokens and reusing them is deprecated; remove this tolerance in a future release + clockTolerance: 3e9, + }); + + if (alg !== TOKEN_ALG) { + throw new NotAllowedError(`Illegal alg "${alg}"`); + } + + if (sub !== TOKEN_SUB) { + throw new NotAllowedError(`Illegal sub "${sub}"`); + } + + // TODO(freben): Passing in tokens without an exp is deprecated; change this warning to an error in a future release + if (typeof exp !== 'number') { + if (!this.warnedForMissingExpClaim) { + this.warnedForMissingExpClaim = true; + this.options.logger.warn( + `#### DEPRECATION WARNING: #### Server-to-server token had no exp claim, support for this has been deprecated and will result in errors in a future release`, + ); + } + } + // TODO(freben): Holding on to tokens and reusing them is deprecated; remove this tolerance in a future release + else if (exp * 1000 < Date.now()) { + if (!this.warnedForExpiredExpClaim) { + this.warnedForExpiredExpClaim = true; + this.options.logger.warn( + `#### DEPRECATION WARNING: #### Server-to-server token had an expired exp claim, support for this has been deprecated and will result in errors in a future release`, + ); + } + } return; } catch (e) { // Catch the verify exception and continue verifyError = e; } } + throw new AuthenticationError(`Invalid server token: ${verifyError}`); } } diff --git a/packages/backend-common/src/tokens/index.ts b/packages/backend-common/src/tokens/index.ts index 43ff12e597..fe1b56df80 100644 --- a/packages/backend-common/src/tokens/index.ts +++ b/packages/backend-common/src/tokens/index.ts @@ -15,4 +15,5 @@ */ export { ServerTokenManager } from './ServerTokenManager'; +export type { ServerTokenManagerOptions } from './ServerTokenManager'; export type { TokenManager } from './types'; diff --git a/packages/backend-common/src/tokens/types.ts b/packages/backend-common/src/tokens/types.ts index 1fea018db9..2fa771b7e2 100644 --- a/packages/backend-common/src/tokens/types.ts +++ b/packages/backend-common/src/tokens/types.ts @@ -20,6 +20,20 @@ * @public */ export interface TokenManager { - getToken: () => Promise<{ token: string }>; - authenticate: (token: string) => Promise; + /** + * Fetches a valid token. + * + * @remarks + * + * Tokens are valid for roughly one hour; the actual deadline is set in the + * payload `exp` claim. Never hold on to tokens for reuse; always ask for a + * new one for each outgoing request. This ensures that you always get a + * valid, fresh one. + */ + getToken(): Promise<{ token: string }>; + + /** + * Validates a given token. + */ + authenticate(token: string): Promise; } diff --git a/packages/catalog-model/examples/all.yaml b/packages/catalog-model/examples/all.yaml index 1101a60ef9..c8e073345c 100644 --- a/packages/catalog-model/examples/all.yaml +++ b/packages/catalog-model/examples/all.yaml @@ -1,7 +1,7 @@ apiVersion: backstage.io/v1alpha1 kind: Location metadata: - name: example-apis + name: example-all description: A collection of all Backstage example entities, except users, groups, and templates spec: targets: diff --git a/packages/core-app-api/src/apis/implementations/auth/saml/types.ts b/packages/core-app-api/src/apis/implementations/auth/saml/types.ts index 55b278b429..e5e32e3457 100644 --- a/packages/core-app-api/src/apis/implementations/auth/saml/types.ts +++ b/packages/core-app-api/src/apis/implementations/auth/saml/types.ts @@ -34,7 +34,6 @@ export const samlSessionSchema: z.ZodSchema = z.object({ picture: z.string().optional(), }), backstageIdentity: z.object({ - id: z.string(), token: z.string(), identity: z.object({ type: z.literal('user'), diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 70d5d6209b..05efac4a62 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/core-components +## 0.9.4-next.2 + +### Patch Changes + +- 52c02ac02b: Don't set the background color on an Avatar component that has a picture. +- 3603014e0e: Add ARIA landmark(
), & label and a heading to OAuthRequestDialog. Removed nested interactive control (button). +- 2025d7c123: Properly highlight `SidebarSubmenuItem` dropdown items on hover, use ellipsis styling on long labels in `SidebarSubmenu`, allow `icon` and `to` properties to be optional on `SidebarSubmenuItem`, and fix `SidebarPage` padding to be responsive to pinned state + ## 0.9.4-next.1 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index ff2b3553c8..e2f05aff2d 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.9.4-next.1", + "version": "0.9.4-next.2", "private": false, "publishConfig": { "access": "public", @@ -55,7 +55,7 @@ "pluralize": "^8.0.0", "prop-types": "^15.7.2", "qs": "^6.9.4", - "rc-progress": "3.2.4", + "rc-progress": "3.3.2", "react-helmet": "6.1.0", "react-hook-form": "^7.12.2", "react-markdown": "^8.0.0", diff --git a/packages/core-components/src/components/Avatar/Avatar.test.tsx b/packages/core-components/src/components/Avatar/Avatar.test.tsx index 1c08d57679..d7bbf712fe 100644 --- a/packages/core-components/src/components/Avatar/Avatar.test.tsx +++ b/packages/core-components/src/components/Avatar/Avatar.test.tsx @@ -17,6 +17,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { Avatar } from './Avatar'; +import { stringToColor } from './utils'; describe('', () => { it('renders without exploding', async () => { @@ -24,4 +25,24 @@ describe('', () => { expect(getByText('JD')).toBeInTheDocument(); }); + + it('generates a background color', async () => { + const bgcolor = stringToColor('John Doe'); + const { getByText } = render(); + expect(getByText('JD')).toHaveStyle(`background-color: ${bgcolor}`); + }); + + it('does not generate a background color when a picture is given', async () => { + const bgcolor = stringToColor('John Doe'); + const { getByAltText } = render( + , + ); + + expect(getByAltText('John Doe')).not.toHaveStyle( + `background-color: ${bgcolor}`, + ); + }); }); diff --git a/packages/core-components/src/components/Avatar/Avatar.tsx b/packages/core-components/src/components/Avatar/Avatar.tsx index 304ee574d2..af8dabf554 100644 --- a/packages/core-components/src/components/Avatar/Avatar.tsx +++ b/packages/core-components/src/components/Avatar/Avatar.tsx @@ -67,15 +67,23 @@ export interface AvatarProps { export function Avatar(props: AvatarProps) { const { displayName, picture, customStyles } = props; const classes = useStyles(); + let styles = { ...customStyles }; + // We only calculate the background color if there's not an avatar + // picture. If there is a picture, it might have a transparent + // background and we don't know whether the calculated background + // color will clash. + if (!picture) { + styles = { + backgroundColor: stringToColor(displayName || ''), + ...customStyles, + }; + } return ( {displayName && extractInitials(displayName)} diff --git a/packages/core-components/src/components/Chip/Chip.stories.tsx b/packages/core-components/src/components/Chip/Chip.stories.tsx index f5cdfd3f16..5e00779209 100644 --- a/packages/core-components/src/components/Chip/Chip.stories.tsx +++ b/packages/core-components/src/components/Chip/Chip.stories.tsx @@ -15,29 +15,51 @@ */ import React from 'react'; -import Chip from '@material-ui/core/Chip'; +import AddIcon from '@material-ui/icons/Add'; +import WarningIcon from '@material-ui/icons/Warning'; +import EditIcon from '@material-ui/icons/Edit'; +import Chip, { ChipProps } from '@material-ui/core/Chip'; + +const icons = { + AddIcon: , + WarningIcon: , + EditIcon: , + None: null, +}; + +const defaultArgs = { + label: 'Label', + size: 'medium', + variant: 'default', + icon: 'None', +}; export default { title: 'Data Display/Chip', component: Chip, + argTypes: { + size: { + options: ['small', 'medium'], + control: { type: 'select' }, + }, + variant: { + options: ['default', 'outlined'], + control: { type: 'select' }, + }, + icon: { + options: Object.keys(icons), + mapping: icons, + control: { + type: 'select', + }, + }, + }, }; -export const Default = () => ; +export const Default = (args: ChipProps) => ; +Default.args = defaultArgs; -export const LargeDeletable = () => ( - ({})} /> +export const Deleteable = (args: ChipProps) => ( + ({})} /> ); - -export const LargeNotDeletable = () => ( - -); - -export const SmallDeletable = () => ( - ({})} /> -); - -export const SmallNotDeletable = () => ( - -); - -export const Outline = () => ; +Deleteable.args = defaultArgs; diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.stories.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.stories.tsx index 449d4a987b..ac341071bf 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.stories.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.stories.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { DismissableBanner } from './DismissableBanner'; +import { DismissableBanner, Props } from './DismissableBanner'; import Typography from '@material-ui/core/Typography'; import { WebStorage } from '@backstage/core-app-api'; import { @@ -29,6 +29,12 @@ import { Link } from '../Link'; export default { title: 'Feedback/DismissableBanner', component: DismissableBanner, + argTypes: { + variant: { + options: ['info', 'error', 'warning'], + control: { type: 'select' }, + }, + }, }; let errorApi: ErrorApi; @@ -39,47 +45,27 @@ const createWebStorage = (): StorageApi => { }; const apis = [[storageApiRef, createWebStorage()] as const]; +const defaultArgs = { + message: 'This is a dismissable banner', + variant: 'info', + fixed: false, +}; -export const Default = () => ( +export const Default = (args: Props) => (
- +
); -export const Error = () => ( -
- - - -
-); +Default.args = defaultArgs; -export const EmojisIncluded = () => ( -
- - - -
-); - -export const WithLink = () => ( +export const WithLink = (args: Props) => (
This is a dismissable banner with a link:{' '} @@ -88,34 +74,10 @@ export const WithLink = () => ( } - variant="info" id="linked_dismissable" />
); -export const Fixed = () => ( -
- - - -
-); - -export const Warning = () => ( -
- - - -
-); +WithLink.args = defaultArgs; diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx index 9ff7616c45..99113fcdb1 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx @@ -87,7 +87,7 @@ const useStyles = makeStyles( { name: 'BackstageDismissableBanner' }, ); -type Props = { +export type Props = { variant: 'info' | 'error' | 'warning'; message: ReactNode; id: string; diff --git a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx index 61131bad9b..8d8416a241 100644 --- a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx +++ b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx @@ -37,6 +37,7 @@ spec: type Props = { annotation: string; + readMoreUrl?: string; }; export type MissingAnnotationEmptyStateClassKey = 'code'; @@ -53,7 +54,10 @@ const useStyles = makeStyles( ); export function MissingAnnotationEmptyState(props: Props) { - const { annotation } = props; + const { annotation, readMoreUrl } = props; + const url = + readMoreUrl || + 'https://backstage.io/docs/features/software-catalog/well-known-annotations'; const classes = useStyles(); const description = ( <> @@ -81,11 +85,7 @@ export function MissingAnnotationEmptyState(props: Props) { customStyle={{ background: 'inherit', fontSize: '115%' }} /> - diff --git a/packages/core-components/src/components/SimpleStepper/SimpleStepper.stories.tsx b/packages/core-components/src/components/SimpleStepper/SimpleStepper.stories.tsx index aa6846bc8f..2f3f26f23e 100644 --- a/packages/core-components/src/components/SimpleStepper/SimpleStepper.stories.tsx +++ b/packages/core-components/src/components/SimpleStepper/SimpleStepper.stories.tsx @@ -16,7 +16,7 @@ import TextField from '@material-ui/core/TextField'; import React, { useState } from 'react'; -import { SimpleStepper } from './SimpleStepper'; +import { SimpleStepper, StepperProps } from './SimpleStepper'; import { SimpleStepperStep } from './SimpleStepperStep'; export default { @@ -24,8 +24,13 @@ export default { component: SimpleStepper, }; -export const Default = () => ( - +const defaultArgs = { + elevated: false, + activeStep: 0, +}; + +export const Default = (args: StepperProps) => ( +
This is the content for step 1
@@ -38,11 +43,13 @@ export const Default = () => (
); -export const ConditionalButtons = () => { +Default.args = defaultArgs; + +export const ConditionalButtons = (args: StepperProps) => { const [required, setRequired] = useState(false); return ( - + { ); }; -export const CompletionStep = () => { +ConditionalButtons.args = defaultArgs; + +export const CompletionStep = (args: StepperProps) => { return ( - +
This is the content for step 1
@@ -80,3 +89,5 @@ export const CompletionStep = () => {
); }; + +CompletionStep.args = defaultArgs; diff --git a/packages/core-components/src/layout/Header/Header.stories.tsx b/packages/core-components/src/layout/Header/Header.stories.tsx index 9fee6313e9..19871dfc75 100644 --- a/packages/core-components/src/layout/Header/Header.stories.tsx +++ b/packages/core-components/src/layout/Header/Header.stories.tsx @@ -21,6 +21,22 @@ import { Header } from './Header'; export default { title: 'Layout/Header', component: Header, + argTypes: { + type: { + options: [ + 'home', + 'tool', + 'service', + 'website', + 'library', + 'app', + 'apis', + 'documentation', + 'other', + ], + control: { type: 'select' }, + }, + }, }; const labels = ( @@ -31,80 +47,21 @@ const labels = ( ); -export const Home = () => ( - -
- {labels} -
-
-); +export const Default = (args: { + type: string; + title: string; + subtitle: string; +}) => { + const { type } = args; + return ( + +
{labels}
+
+ ); +}; -export const HomeWithSubtitle = () => ( -
- {labels} -
-); - -export const Apis = () => ( - -
- {labels} -
-
-); - -export const Tool = () => ( - -
- {labels} -
-
-); - -export const Service = () => ( - -
- {labels} -
-
-); - -export const Website = () => ( - -
- {labels} -
-
-); - -export const Library = () => ( - -
- {labels} -
-
-); - -export const App = () => ( - -
- {labels} -
-
-); - -export const Documentation = () => ( - -
- {labels} -
-
-); - -export const Other = () => ( - -
- {labels} -
-
-); +Default.args = { + type: 'home', + title: 'This is a title', + subtitle: 'This is a subtitle', +}; diff --git a/packages/core-components/src/layout/InfoCard/InfoCard.stories.tsx b/packages/core-components/src/layout/InfoCard/InfoCard.stories.tsx index 8dd8272f5a..a6509caaaf 100644 --- a/packages/core-components/src/layout/InfoCard/InfoCard.stories.tsx +++ b/packages/core-components/src/layout/InfoCard/InfoCard.stories.tsx @@ -18,9 +18,7 @@ import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router'; -import { InfoCard } from './InfoCard'; - -const linkInfo = { title: 'Go to XYZ Location', link: '#' }; +import { InfoCard, Props } from './InfoCard'; export default { title: 'Layout/Information Card', @@ -38,6 +36,11 @@ const text = ( ); +const defaultProps = { + title: 'Information Card', + subheader: 'Subheader', +}; + const Wrapper = ({ children }: PropsWithChildren<{}>) => ( @@ -48,24 +51,21 @@ const Wrapper = ({ children }: PropsWithChildren<{}>) => ( ); -export const Default = () => ( +export const Default = (args: Props) => ( - {text} + {text} ); -export const Subhead = () => ( +Default.args = defaultProps; + +export const LinkInFooter = (args: Props) => ( - - {text} - + {text} ); -export const LinkInFooter = () => ( - - - {text} - - -); +LinkInFooter.args = { + ...defaultProps, + deepLink: { title: 'Go to XYZ Location', link: '#' }, +}; diff --git a/packages/core-components/src/layout/InfoCard/InfoCard.tsx b/packages/core-components/src/layout/InfoCard/InfoCard.tsx index 256d60cfa2..831c8f95d9 100644 --- a/packages/core-components/src/layout/InfoCard/InfoCard.tsx +++ b/packages/core-components/src/layout/InfoCard/InfoCard.tsx @@ -125,7 +125,7 @@ export type InfoCardVariants = 'flex' | 'fullHeight' | 'gridItem'; * * `...` */ -type Props = { +export type Props = { title?: ReactNode; subheader?: ReactNode; divider?: boolean; diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 4a0376946a..c004f6904c 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -369,6 +369,16 @@ const SidebarItemBase = forwardRef((props, ref) => { // Still waiting on a Q answered to fine tune the implementation const { isOpen } = useContext(SidebarContext); + const divStyle = + !isOpen && children ? { display: 'flex', marginLeft: '24px' } : {}; + + const displayItemIcon = ( +
+ + {!isOpen && children ? : <>} +
+ ); + const itemIcon = ( ((props, ref) => { invisible={!hasNotifications} className={classnames({ [classes.closedItemIcon]: !isOpen })} > - + {displayItemIcon} ); diff --git a/packages/create-app/package.json b/packages/create-app/package.json index cf3bafecd8..6d1d2ba402 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -91,6 +91,8 @@ "@backstage/plugin-search-backend-node": "", "@backstage/plugin-tech-radar": "", "@backstage/plugin-techdocs": "", + "@backstage/plugin-techdocs-react": "", + "@backstage/plugin-techdocs-module-addons-contrib": "", "@backstage/plugin-techdocs-backend": "", "@backstage/plugin-user-settings": "", "@backstage/test-utils": "", diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index b6c93a38b3..25007d7535 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -75,6 +75,8 @@ import { version as pluginSearchBackendModulePg } from '../../../../plugins/sear import { version as pluginSearchBackendNode } from '../../../../plugins/search-backend-node/package.json'; import { version as pluginTechRadar } from '../../../../plugins/tech-radar/package.json'; import { version as pluginTechdocs } from '../../../../plugins/techdocs/package.json'; +import { version as pluginTechdocsReact } from '../../../../plugins/techdocs-react/package.json'; +import { version as pluginTechdocsModuleAddonsContrib } from '../../../../plugins/techdocs-module-addons-contrib/package.json'; import { version as pluginTechdocsBackend } from '../../../../plugins/techdocs-backend/package.json'; import { version as pluginUserSettings } from '../../../../plugins/user-settings/package.json'; @@ -120,6 +122,9 @@ export const packageVersions = { '@backstage/plugin-search-backend-node': pluginSearchBackendNode, '@backstage/plugin-tech-radar': pluginTechRadar, '@backstage/plugin-techdocs': pluginTechdocs, + '@backstage/plugin-techdocs-react': pluginTechdocsReact, + '@backstage/plugin-techdocs-module-addons-contrib': + pluginTechdocsModuleAddonsContrib, '@backstage/plugin-techdocs-backend': pluginTechdocsBackend, '@backstage/plugin-user-settings': pluginUserSettings, '@backstage/test-utils': testUtils, 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 87a8060594..9bf67f6e52 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 @@ -28,6 +28,8 @@ "@backstage/plugin-search-react": "^{{version '@backstage/plugin-search-react'}}", "@backstage/plugin-tech-radar": "^{{version '@backstage/plugin-tech-radar'}}", "@backstage/plugin-techdocs": "^{{version '@backstage/plugin-techdocs'}}", + "@backstage/plugin-techdocs-react": "^{{version '@backstage/plugin-techdocs-react'}}", + "@backstage/plugin-techdocs-module-addons-contrib": "^{{version '@backstage/plugin-techdocs-module-addons-contrib'}}", "@backstage/plugin-user-settings": "^{{version '@backstage/plugin-user-settings'}}", "@backstage/theme": "^{{version '@backstage/theme'}}", "@material-ui/core": "^4.12.2", 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 f4ff424926..c4877263f0 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 @@ -19,6 +19,8 @@ import { techdocsPlugin, TechDocsReaderPage, } from '@backstage/plugin-techdocs'; +import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; +import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; import { UserSettingsPage } from '@backstage/plugin-user-settings'; import { apis } from './apis'; import { entityPage } from './components/catalog/EntityPage'; @@ -68,7 +70,11 @@ const routes = ( } - /> + > + + + + } /> } /> { url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', result: 'https://gitlab.example.com/a/b/raw/master/c.yaml', }, + { + config: configWithNoToken, + url: 'https://gitlab.example.com/a/b/repo/blob/master/c.yaml', + result: 'https://gitlab.example.com/a/b/repo/raw/master/c.yaml', + }, + { + config: configWithNoToken, + url: 'https://gitlab.example.com/a/blob/blob/master/c.yaml', + result: 'https://gitlab.example.com/a/blob/raw/master/c.yaml', + }, + { + config: configWithNoToken, + url: 'https://gitlab.example.com/a/b/blob/blob/c.yaml', + result: 'https://gitlab.example.com/a/b/raw/blob/c.yaml', + }, + { + config: configWithNoToken, + url: 'https://gitlab.example.com/a//blob/blob/c.yaml', + result: 'https://gitlab.example.com/a/blob/raw/c.yaml', + }, ])('should handle happy path %#', async ({ config, url, result }) => { await expect(getGitLabFileFetchUrl(url, config)).resolves.toBe(result); }); diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index b379d3d129..ba0f9c83de 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -16,6 +16,7 @@ import { GitLabIntegrationConfig } from './config'; import fetch from 'cross-fetch'; +import { InputError } from '@backstage/errors'; /** * Given a URL pointing to a file on a provider, returns a URL that is suitable @@ -66,31 +67,34 @@ export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { } // Converts -// from: https://gitlab.example.com/a/b/blob/master/c.yaml -// to: https://gitlab.example.com/a/b/raw/master/c.yaml +// from: https://gitlab.example.com/groupA/teams/repoA/blob/master/c.yaml +// to: https://gitlab.example.com/groupA/teams/repoA/raw/master/c.yaml export function buildRawUrl(target: string): URL { try { const url = new URL(target); - const [empty, userOrOrg, repoName, blobKeyword, ...restOfPath] = - url.pathname.split('/'); + const splitPath = url.pathname.split('/').filter(Boolean); - if ( - empty !== '' || - userOrOrg === '' || - repoName === '' || - blobKeyword !== 'blob' || - !restOfPath.join('/').match(/\.(yaml|yml)$/) - ) { - throw new Error('Wrong GitLab URL'); + // Check blob existence + const blobIndex = splitPath.indexOf('blob', 2); + if (blobIndex < 2 || blobIndex === splitPath.length - 1) { + throw new InputError('Wrong GitLab URL'); + } + + // Take repo path + const repoPath = splitPath.slice(0, blobIndex); + const restOfPath = splitPath.slice(blobIndex + 1); + + if (!restOfPath.join('/').match(/\.(yaml|yml)$/)) { + throw new InputError('Wrong GitLab URL'); } // Replace 'blob' with 'raw' - url.pathname = [empty, userOrOrg, repoName, 'raw', ...restOfPath].join('/'); + url.pathname = [...repoPath, 'raw', ...restOfPath].join('/'); return url; } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); + throw new InputError(`Incorrect url: ${target}, ${e}`); } } diff --git a/packages/techdocs-cli/src/lib/httpServer.ts b/packages/techdocs-cli/src/lib/httpServer.ts index 92fc5abc87..c4bd5b823a 100644 --- a/packages/techdocs-cli/src/lib/httpServer.ts +++ b/packages/techdocs-cli/src/lib/httpServer.ts @@ -32,7 +32,7 @@ export default class HTTPServer { mkdocsPort: number, verbose: boolean, ) { - this.proxyEndpoint = '/api/'; + this.proxyEndpoint = '/api/techdocs/'; this.backstageBundleDir = backstageBundleDir; this.backstagePort = backstagePort; this.mkdocsPort = mkdocsPort; @@ -46,10 +46,9 @@ export default class HTTPServer { }); return (request: http.IncomingMessage): [httpProxy, string] => { - // If the request goes to /api/ we want to remove /api/ from the prefix of the request URL. - // e.g. ['/', 'api', pathChunks] - const [, , ...pathChunks] = request.url?.split('/') ?? []; - const forwardPath = pathChunks.join('/'); + // If the request path is prefixed with this.proxyEndpoint, remove it. + const proxyEndpointPath = new RegExp(`^${this.proxyEndpoint}`, 'i'); + const forwardPath = request.url?.replace(proxyEndpointPath, '') || ''; return [proxy, forwardPath]; }; diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 4e8dc1cd41..4426a54a77 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/dev-utils": "^1.0.2-next.2", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 2dfb48cbc1..458aa61709 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 72214dc6c7..7294b4c49c 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 9034e0bb07..bb0be9d439 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -23,7 +23,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index c4ebbc6f48..ddf837493b 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -35,7 +35,7 @@ "dependencies": { "@asyncapi/react-component": "1.0.0-next.38", "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog": "^1.2.0-next.2", "@backstage/plugin-catalog-react": "^1.1.0-next.2", @@ -44,6 +44,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "graphiql": "^1.8.8", + "graphql-ws": "^5.4.1", "graphql": "^16.0.0", "isomorphic-form-data": "^2.0.0", "react-router": "6.0.0-beta.0", diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index a38197668e..bb25ff6d57 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -586,11 +586,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { handlers: OAuthHandlers, options: Pick< Options, - | 'providerId' - | 'persistScopes' - | 'disableRefresh' - | 'tokenIssuer' - | 'callbackUrl' + 'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl' >, ): OAuthAdapter; // (undocumented) diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index 0ce9dff66c..d6d346745a 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -60,7 +60,6 @@ describe('OAuthAdapter', () => { const oAuthProviderOptions = { providerId: 'test-provider', secure: false, - disableRefresh: true, appOrigin: 'http://localhost:3000', cookieDomain: 'example.com', cookiePath: '/auth/test-provider', @@ -110,7 +109,6 @@ describe('OAuthAdapter', () => { it('sets the refresh cookie if refresh is enabled', async () => { const oauthProvider = new OAuthAdapter(providerInstance, { ...oAuthProviderOptions, - disableRefresh: false, isOriginAllowed: () => false, }); @@ -153,7 +151,6 @@ describe('OAuthAdapter', () => { }; const oauthProvider = new OAuthAdapter(handlers, { ...oAuthProviderOptions, - disableRefresh: false, persistScopes: true, }); @@ -238,36 +235,9 @@ describe('OAuthAdapter', () => { ); }); - it('does not set the refresh cookie if refresh is disabled', async () => { - const oauthProvider = new OAuthAdapter(providerInstance, { - ...oAuthProviderOptions, - disableRefresh: true, - isOriginAllowed: () => false, - }); - - const mockRequest = { - cookies: { - 'test-provider-nonce': 'nonce', - }, - query: { - state: 'nonce', - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.frameHandler(mockRequest, mockResponse); - expect(mockResponse.cookie).toHaveBeenCalledTimes(0); - }); - it('removes refresh cookie when logging out', async () => { const oauthProvider = new OAuthAdapter(providerInstance, { ...oAuthProviderOptions, - disableRefresh: false, isOriginAllowed: () => false, }); @@ -292,10 +262,8 @@ describe('OAuthAdapter', () => { }); it('gets new access-token when refreshing', async () => { - oAuthProviderOptions.disableRefresh = false; const oauthProvider = new OAuthAdapter(providerInstance, { ...oAuthProviderOptions, - disableRefresh: false, isOriginAllowed: () => false, }); @@ -327,26 +295,6 @@ describe('OAuthAdapter', () => { }); }); - it('handles refresh without capabilities', async () => { - const oauthProvider = new OAuthAdapter(providerInstance, { - ...oAuthProviderOptions, - disableRefresh: true, - isOriginAllowed: () => false, - }); - - const mockRequest = { - header: () => 'XMLHttpRequest', - } as unknown as express.Request; - - const mockResponse = {} as unknown as express.Response; - - await expect( - oauthProvider.refresh(mockRequest, mockResponse), - ).rejects.toThrow( - 'Refresh token is not supported for provider test-provider', - ); - }); - it('sets the correct cookie configuration using a callbackUrl', async () => { const config = { baseUrl: 'http://domain.org/auth', diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 637dc1cff2..5be4b7e3c0 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -48,7 +48,6 @@ export const TEN_MINUTES_MS = 600 * 1000; export type Options = { providerId: string; secure: boolean; - disableRefresh?: boolean; persistScopes?: boolean; cookieDomain: string; cookiePath: string; @@ -64,11 +63,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { handlers: OAuthHandlers, options: Pick< Options, - | 'providerId' - | 'persistScopes' - | 'disableRefresh' - | 'tokenIssuer' - | 'callbackUrl' + 'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl' >, ): OAuthAdapter { const { origin: appOrigin } = new URL(config.appUrl); @@ -170,7 +165,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { response.providerInfo.scope = state.scope; } - if (refreshToken && !this.options.disableRefresh) { + if (refreshToken) { // set new refresh token this.setRefreshTokenCookie(res, refreshToken); } @@ -210,7 +205,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { throw new AuthenticationError('Invalid X-Requested-With header'); } - if (!this.handlers.refresh || this.options.disableRefresh) { + if (!this.handlers.refresh) { throw new InputError( `Refresh token is not supported for provider ${this.options.providerId}`, ); diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 3181314540..9ddd587508 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -243,7 +243,6 @@ export const auth0 = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: true, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/bitbucket/provider.ts b/plugins/auth-backend/src/providers/bitbucket/provider.ts index 905181333a..5b9919764b 100644 --- a/plugins/auth-backend/src/providers/bitbucket/provider.ts +++ b/plugins/auth-backend/src/providers/bitbucket/provider.ts @@ -261,7 +261,6 @@ export const bitbucket = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index 23867f6990..868357bcda 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -248,7 +248,6 @@ export const gitlab = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index 233e28f750..2d58bc2aa6 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -238,7 +238,6 @@ export const google = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/microsoft/provider.ts b/plugins/auth-backend/src/providers/microsoft/provider.ts index 0a4b67d667..0c58049619 100644 --- a/plugins/auth-backend/src/providers/microsoft/provider.ts +++ b/plugins/auth-backend/src/providers/microsoft/provider.ts @@ -267,7 +267,6 @@ export const microsoft = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index 8e0250cf2f..6b4787e985 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -43,6 +43,7 @@ import { SignInResolver, } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; +import { InputError } from '@backstage/errors'; type PrivateInfo = { refreshToken: string; @@ -56,6 +57,7 @@ export type OAuth2AuthProviderOptions = OAuthProviderOptions & { scope?: string; resolverContext: AuthResolverContext; includeBasicAuth?: boolean; + disableRefresh?: boolean; }; export class OAuth2AuthProvider implements OAuthHandlers { @@ -63,11 +65,13 @@ export class OAuth2AuthProvider implements OAuthHandlers { private readonly signInResolver?: SignInResolver; private readonly authHandler: AuthHandler; private readonly resolverContext: AuthResolverContext; + private readonly disableRefresh: boolean; constructor(options: OAuth2AuthProviderOptions) { this.signInResolver = options.signInResolver; this.authHandler = options.authHandler; this.resolverContext = options.resolverContext; + this.disableRefresh = options.disableRefresh ?? false; this._strategy = new OAuth2Strategy( { @@ -132,6 +136,9 @@ export class OAuth2AuthProvider implements OAuthHandlers { } async refresh(req: OAuthRefreshRequest) { + if (this.disableRefresh) { + throw new InputError('Session refreshes have been disabled'); + } const refreshTokenResponse = await executeRefreshTokenStrategy( this._strategy, req.refreshToken, @@ -243,10 +250,10 @@ export const oauth2 = createAuthProviderIntegration({ scope, includeBasicAuth, resolverContext, + disableRefresh, }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index aba9048cc7..69a65d1cae 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -262,7 +262,6 @@ export const oidc = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 4e05ff4487..98cec6df3a 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -271,7 +271,6 @@ export const okta = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/auth-backend/src/providers/onelogin/provider.ts b/plugins/auth-backend/src/providers/onelogin/provider.ts index 7dcc6455ac..d81eb3d83c 100644 --- a/plugins/auth-backend/src/providers/onelogin/provider.ts +++ b/plugins/auth-backend/src/providers/onelogin/provider.ts @@ -238,7 +238,6 @@ export const onelogin = createAuthProviderIntegration({ }); return OAuthAdapter.fromConfig(globalConfig, provider, { - disableRefresh: false, providerId, callbackUrl, }); diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 186d50559c..e616fa3b75 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-azure-devops-common": "^0.2.3-next.0", diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 43c8aa3b28..8e557f45e1 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index 0179fe9465..f2e9132e91 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -27,7 +27,7 @@ "@backstage/catalog-client": "^1.0.2-next.0", "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/cli": "^0.17.1-next.2", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog": "^1.2.0-next.2", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 6644646029..d04831ab6d 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/catalog-graph/README.md b/plugins/catalog-graph/README.md index 0034cf0c3b..33dee92935 100644 --- a/plugins/catalog-graph/README.md +++ b/plugins/catalog-graph/README.md @@ -83,3 +83,9 @@ To use the catalog graph plugin, you have to add some things to your Backstage a ``` + +## Development + +Run `yarn` in the root of this plugin to install all dependencies and then `yarn start` to run a [development version](./dev/index.tsx) of this plugin. + +![dev](https://user-images.githubusercontent.com/1190768/167130527-14d787ce-510d-408a-8f93-45bb94b3a9af.png) diff --git a/plugins/catalog-graph/dev/index.tsx b/plugins/catalog-graph/dev/index.tsx index 7d772702a1..1ef9f676de 100644 --- a/plugins/catalog-graph/dev/index.tsx +++ b/plugins/catalog-graph/dev/index.tsx @@ -13,14 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { GetEntitiesResponse } from '@backstage/catalog-client'; import { - Entity, + GetEntitiesResponse, + GetEntityFacetsRequest, + GetEntityFacetsResponse, +} from '@backstage/catalog-client'; +import { CompoundEntityRef, DEFAULT_NAMESPACE, + Entity, RELATION_API_CONSUMED_BY, RELATION_API_PROVIDED_BY, RELATION_CONSUMES_API, + RELATION_DEPENDENCY_OF, + RELATION_DEPENDS_ON, RELATION_HAS_PART, RELATION_OWNED_BY, RELATION_OWNER_OF, @@ -30,22 +36,24 @@ import { } from '@backstage/catalog-model'; import { Content, Header, Page } from '@backstage/core-components'; import { createDevApp } from '@backstage/dev-utils'; +import { CatalogEntityPage } from '@backstage/plugin-catalog'; import { CatalogApi, catalogApiRef, EntityProvider, } from '@backstage/plugin-catalog-react'; +import { JsonObject } from '@backstage/types'; import { Grid } from '@material-ui/core'; +import _ from 'lodash'; import React from 'react'; import { CatalogGraphPage, catalogGraphPlugin, EntityCatalogGraphCard, } from '../src'; -import { CatalogEntityPage } from '@backstage/plugin-catalog'; type DataRelation = [string, string, string]; -type DataEntity = [string, string, DataRelation[]]; +type DataEntity = [string, string, DataRelation[], JsonObject?]; const entities = ( [ @@ -75,8 +83,19 @@ const entities = ( [RELATION_OWNED_BY, 'Group', 'team-a'], [RELATION_PART_OF, 'System', 'wayback'], [RELATION_PROVIDES_API, 'API', 'wayback-api'], + [RELATION_DEPENDS_ON, 'Resource', 'wayback-archive-storage'], ], ], + [ + 'Resource', + 'wayback-archive-storage', + [ + [RELATION_OWNED_BY, 'Group', 'team-a'], + [RELATION_PART_OF, 'System', 'wayback'], + [RELATION_DEPENDENCY_OF, 'Component', 'wayback-archive'], + ], + { type: 's3-bucket' }, + ], [ 'Component', 'wayback-search', @@ -84,8 +103,19 @@ const entities = ( [RELATION_OWNED_BY, 'Group', 'team-a'], [RELATION_PART_OF, 'System', 'wayback'], [RELATION_CONSUMES_API, 'API', 'wayback-api'], + [RELATION_DEPENDS_ON, 'Resource', 'wayback-search-db'], ], ], + [ + 'Resource', + 'wayback-search-db', + [ + [RELATION_OWNED_BY, 'Group', 'team-a'], + [RELATION_PART_OF, 'System', 'wayback'], + [RELATION_DEPENDENCY_OF, 'Component', 'wayback-search'], + ], + { type: 'database' }, + ], [ 'API', 'wayback-api', @@ -101,7 +131,9 @@ const entities = ( 'team-a', [ [RELATION_OWNER_OF, 'Component', 'wayback-archive'], + [RELATION_OWNER_OF, 'Resource', 'wayback-archive-storage'], [RELATION_OWNER_OF, 'Component', 'wayback-search'], + [RELATION_OWNER_OF, 'Resource', 'wayback-search-db'], [RELATION_OWNER_OF, 'API', 'wayback-api'], [RELATION_OWNER_OF, 'Domain', 'wayback'], [RELATION_OWNER_OF, 'System', 'wayback'], @@ -109,7 +141,7 @@ const entities = ( ], ] as DataEntity[] ).reduce((o, d) => { - const [kind, name, relations] = d; + const [kind, name, relations, spec] = d; const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', @@ -117,6 +149,7 @@ const entities = ( metadata: { name, }, + spec: spec, relations: relations.map(([type, k, n]) => ({ target: { kind: k, name: n, namespace: DEFAULT_NAMESPACE }, targetRef: stringifyEntityRef({ @@ -149,6 +182,25 @@ createDevApp() async getEntities(): Promise { return { items: Object.values(entities) }; }, + async getEntityFacets( + request: GetEntityFacetsRequest, + ): Promise { + if (request.facets.includes('kind')) { + const kinds: [string, number][] = _.chain(entities) + .map(e => e.kind) + .groupBy(k => k) + .mapValues(v => v.length) + .toPairs() + .value(); + const kindFacet = kinds.map(([kind, count]) => ({ + value: kind, + count: count, + })); + + return { facets: { kind: kindFacet } }; + } + return { facets: {} }; + }, } as Partial as unknown as CatalogApi; }, }) diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index a625abe964..79f98c06a7 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-client": "^1.0.2-next.0", "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", @@ -50,6 +50,7 @@ "@backstage/core-app-api": "^1.0.2-next.1", "@backstage/dev-utils": "^1.0.2-next.2", "@backstage/test-utils": "^1.1.0-next.2", + "@backstage/types": "^1.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx index 233553620a..e7bf10216f 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx @@ -109,7 +109,7 @@ describe('', () => { ); await userEvent.click(getByRole('combobox')); - userEvent.tab(); + await userEvent.tab(); await waitFor(() => { expect(onChange).toBeCalledWith(undefined); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx index 8d5acf282c..6bd740ac9e 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx @@ -101,7 +101,7 @@ describe('', () => { ); await userEvent.click(getByRole('combobox')); - userEvent.tab(); + await userEvent.tab(); await waitFor(() => { expect(onChange).toBeCalledWith(undefined); diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 6a46b285dd..3df0de7a07 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -37,7 +37,7 @@ "@backstage/catalog-client": "^1.0.2-next.0", "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/integration": "^1.2.0-next.1", diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx index 20b4bc986e..90a2987958 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx @@ -67,7 +67,7 @@ describe('', () => { ); await act(async () => { - userEvent.clear(getByLabelText('Main Field')); + await userEvent.clear(getByLabelText('Main Field')); await userEvent.type(getByLabelText('Main Field'), 'My Text'); await userEvent.click(getByRole('button', { name: /submit/i })); }); diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/common.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/common.tsx index 79a3c69955..d2bc6312dd 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/common.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/common.tsx @@ -89,26 +89,30 @@ export function Container(props: { ); } +// Extracts a link from a value, if possible +function findLink(value: string): string | undefined { + if (value.match(/^url:https?:\/\//)) { + return value.slice('url:'.length); + } + if (value.match(/^https?:\/\//)) { + return value; + } + return undefined; +} + export function KeyValueListItem(props: { indent?: boolean; entry: [string, string]; }) { const [key, value] = props.entry; + const link = findLink(value); + return ( {props.indent && } - {value.substring(0, 4)} - {value.substring(4)} - - ) - } + secondary={link ? {value} : value} /> ); diff --git a/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx b/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx index 8e8c1b24d7..464531a4d9 100644 --- a/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx +++ b/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx @@ -96,7 +96,13 @@ export function useEntityTypeFilter(): { } // Sort by facet count descending, so the most common types appear on top - const newTypes = sortBy(facets, f => -f.count).map(f => f.value); + const newTypes = [ + ...new Set( + sortBy(facets, f => -f.count).map(f => + f.value.toLocaleLowerCase('en-US'), + ), + ), + ]; setAvailableTypes(newTypes); // Update type filter to only valid values when the list of available types has changed diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 2d401fff83..c78bcf5c20 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -36,7 +36,7 @@ "dependencies": { "@backstage/catalog-client": "^1.0.2-next.0", "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/integration-react": "^1.1.0-next.2", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index a0a15027ed..7d59e52fe2 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 2397d82068..6d016c1352 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 404dcb840a..475f6aa9cc 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 4246ab856a..cbf0a18e68 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index 821c3e30c2..128d5200d2 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -30,7 +30,7 @@ "@material-ui/core": "^4.9.10", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", - "rc-progress": "3.2.4", + "rc-progress": "3.3.2", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, @@ -44,7 +44,7 @@ "@backstage/test-utils": "^1.1.0-next.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", - "@testing-library/user-event": "^13.1.8", + "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", "msw": "^0.35.0", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index b6fe2a66b2..0a4e160dc8 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/theme": "^0.2.15", diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index ca16d9625e..b9dd30d439 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -36,7 +36,7 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index d30ee9c150..46a3789e62 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -21,7 +21,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index dea9e4d50a..dcd190861e 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/plugin-explore-react": "^0.0.17-next.0", diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index b60a8a3aee..93dab0b183 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -25,7 +25,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.1", "@backstage/theme": "^0.2.15", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 0fbc363f27..09e41c2e7f 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index b6adb960c9..aff29d7e07 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 46f4dde6eb..a3537c71c1 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/integration": "^1.2.0-next.0", "@backstage/theme": "^0.2.15", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index eb1f0337f6..c4b2d7438f 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/integration": "^1.2.0-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 2f1f133f23..3dee550bf7 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/integration": "^1.2.0-next.1", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 3be80e7291..2fedb7d6df 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -35,7 +35,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index a02b7fd821..6d7f273447 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index de2f49ff83..99903cb63c 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -34,13 +34,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "graphiql": "^1.5.12", + "graphql-ws": "^5.4.1", "graphql": "^16.0.0", "react-use": "^17.2.4" }, diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index e70e0475c9..97db023fc1 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-home +## 0.4.21-next.3 + +### Patch Changes + +- 69093c5f91: Display entity titles in `StarredEntities` home page card (if defined) and don't show entities which no longer exist +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + ## 0.4.21-next.2 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 0d1d793cf3..68a683dc31 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.21-next.2", + "version": "0.4.21-next.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/plugin-stack-overflow": "^0.1.1-next.2", diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 2051239647..b40b2b9e0e 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index d73752c215..f77afe86e5 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 390042c1a1..e1c452496b 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 62acec4f98..cad2a5bcc3 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kubernetes-backend +## 0.5.1-next.2 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.2.10-next.1 + ## 0.5.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 1ee86e527a..8e2f143e7f 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.5.1-next.1", + "version": "0.5.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", "@backstage/errors": "^1.0.0", - "@backstage/plugin-kubernetes-common": "^0.2.10-next.0", + "@backstage/plugin-kubernetes-common": "^0.2.10-next.1", "@google-cloud/container": "^3.0.0", "@kubernetes/client-node": "^0.16.0", "@types/express": "^4.17.6", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 35e3fef6f0..cdc209f88f 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-common +## 0.2.10-next.1 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. + ## 0.2.10-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 1be085d7c7..d250e82780 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.2.10-next.0", + "version": "0.2.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 8d5b23fd74..dda45a0409 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.6.5-next.3 + +### Patch Changes + +- 447e060872: Add support for 'oidc' as authProvider for kubernetes authentication + and adds optional 'oidcTokenProvider' config value. This will allow + users to authenticate to kubernetes cluster using id tokens obtained + from the configured auth provider in their backstage instance. +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.2.10-next.1 + - @backstage/core-components@0.9.4-next.2 + ## 0.6.5-next.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 4502a051a6..61885408e8 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.6.5-next.2", + "version": "0.6.5-next.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,10 +36,10 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", - "@backstage/plugin-kubernetes-common": "^0.2.10-next.0", + "@backstage/plugin-kubernetes-common": "^0.2.10-next.1", "@backstage/theme": "^0.2.15", "@kubernetes/client-node": "^0.16.0", "@material-ui/core": "^4.12.2", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 01cc4c1475..59aca403ac 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -37,7 +37,7 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 31fd91d871..a8ca2bd9e6 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 9ffad6178b..d0d8e66787 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -35,7 +35,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 039aa47252..7a99844dea 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-org +## 0.5.5-next.3 + +### Patch Changes + +- 2025d7c123: Include namespace in `MyGroupSidebarItem` if not default and remove root item routing if there are multiple groups +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + ## 0.5.5-next.2 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 1dde634de6..1eba133f18 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.5.5-next.2", + "version": "0.5.5-next.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index bae53e1cac..35e6ecefa9 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 8f1f5c41d0..804baccc84 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index d749ff77fc..2b6056b6e6 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index a58daace55..88cee84d7e 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-scaffolder +## 1.2.0-next.3 + +### Patch Changes + +- cc8ddd0979: revert dependency `event-source-polyfill` to `1.0.25` +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + ## 1.2.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 7b2e255551..6795af4488 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.2.0-next.2", + "version": "1.2.0-next.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/catalog-client": "^1.0.2-next.0", "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/integration": "^1.2.0-next.1", @@ -92,7 +92,7 @@ "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "event-source-polyfill": "1.0.26", + "event-source-polyfill": "1.0.25", "msw": "^0.35.0" }, "files": [ diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts index 134de5a9f6..24ceec2875 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts @@ -438,6 +438,50 @@ describe('ElasticSearchSearchEngine', () => { }); }); + it('should perform search query with less results than one page', async () => { + mock.clear({ + method: 'POST', + path: '/*__search/_search', + }); + mock.add( + { + method: 'POST', + path: '/*__search/_search', + }, + () => { + return { + hits: { + total: { value: 20, relation: 'eq' }, + hits: Array(20) + .fill(null) + .map((_, i) => ({ + _index: 'mytype-index__', + _source: { + value: `${i}`, + }, + })), + }, + }; + }, + ); + + const mockedSearchResult = await testSearchEngine.query({ + term: 'testTerm', + filters: {}, + }); + + expect(mockedSearchResult).toMatchObject({ + results: expect.arrayContaining( + Array(20) + .fill(null) + .map((_, i) => ({ + type: 'mytype', + document: { value: `${i}` }, + })), + ), + }); + }); + it('should perform search query with more results than one page', async () => { mock.clear({ method: 'POST', diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 5ec33a95e3..00c25905c3 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -268,7 +268,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { body: elasticSearchQuery, }); const { page } = decodePageCursor(query.pageCursor); - const hasNextPage = result.body.hits.total.value > page * pageSize; + const hasNextPage = result.body.hits.total.value > (page + 1) * pageSize; const hasPreviousPage = page > 0; const nextPageCursor = hasNextPage ? encodePageCursor({ page: page + 1 }) diff --git a/plugins/search/package.json b/plugins/search/package.json index eda999b1a7..109ed2a455 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -35,12 +35,12 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", - "@backstage/plugin-search-react": "^0.2.0-next.2", "@backstage/plugin-search-common": "^0.3.4-next.0", + "@backstage/plugin-search-react": "^0.2.0-next.2", "@backstage/theme": "^0.2.15", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index a02df69ab3..2af804803b 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 4953a1810e..b72eb64a5b 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@backstage/types": "^1.0.0", diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 36c52028fb..e41f53d500 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", @@ -46,7 +46,7 @@ "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.10.0", "cross-fetch": "^3.1.5", - "rc-progress": "3.2.4", + "rc-progress": "3.3.2", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 5d948963a3..c7ca761c1e 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-catalog-react": "^1.1.0-next.2", "@backstage/theme": "^0.2.15", diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 762cf64225..7e07f10b33 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/plugin-home": "^0.4.21-next.2", "@backstage/plugin-search-common": "^0.3.4-next.0", diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 198a6b1b26..be53883371 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 477f45c8e0..5821d6036c 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -34,7 +34,7 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/techdocs-addons-test-utils/api-report.md b/plugins/techdocs-addons-test-utils/api-report.md index 14bffbc8b3..3808b65b84 100644 --- a/plugins/techdocs-addons-test-utils/api-report.md +++ b/plugins/techdocs-addons-test-utils/api-report.md @@ -10,31 +10,23 @@ import { screen as screen_2 } from 'testing-library__dom'; import { TechDocsEntityMetadata } from '@backstage/plugin-techdocs-react'; import { TechDocsMetadata } from '@backstage/plugin-techdocs-react'; -// @public (undocumented) +// @public export class TechDocsAddonTester { protected constructor(addons: ReactElement[]); - // (undocumented) atPath(path: string): this; - // (undocumented) build(): React_2.ReactElement< any, string | React_2.JSXElementConstructor >; - // (undocumented) static buildAddonsInTechDocs(addons: ReactElement[]): TechDocsAddonTester; - // (undocumented) renderWithEffects(): Promise< typeof screen_2 & { shadowRoot: ShadowRoot | null; } >; - // (undocumented) - withApis(apis: TechdocsAddonTesterApis): this; - // (undocumented) + withApis(apis: TechdocsAddonTesterApis): this; withDom(dom: ReactElement): this; - // (undocumented) withEntity(entity: Partial): this; - // (undocumented) withMetadata(metadata: Partial): this; } ``` diff --git a/plugins/techdocs-addons-test-utils/src/test-utils.tsx b/plugins/techdocs-addons-test-utils/src/test-utils.tsx index 9d668eaf3d..2c20199038 100644 --- a/plugins/techdocs-addons-test-utils/src/test-utils.tsx +++ b/plugins/techdocs-addons-test-utils/src/test-utils.tsx @@ -65,14 +65,18 @@ type TechDocsAddonTesterTestApiPair = TApi extends infer TImpl : never; /** @ignore */ -type TechdocsAddonTesterApis = TechDocsAddonTesterTestApiPair[]; +type TechdocsAddonTesterApis = { + [TIndex in keyof TApiPairs]: TechDocsAddonTesterTestApiPair< + TApiPairs[TIndex] + >; +}; type TechDocsAddonTesterOptions = { dom: ReactElement; entity: Partial; metadata: Partial; componentId: string; - apis: TechdocsAddonTesterApis; + apis: TechdocsAddonTesterApis; path: string; }; @@ -109,13 +113,27 @@ const defaultDom = ( ); /** + * Utility class for rendering TechDocs Addons end-to-end within the TechDocs + * reader page, with a set of givens (e.g. page DOM, metadata, etc). + * + * @example + * ```tsx + * const { getByText } = await TechDocsAddonTester.buildAddonsInTechDocs([]) + * .withDom(TEST_CONTENT) + * .renderWithEffects(); + * + * expect(getByText('TEST_CONTENT')).toBeInTheDocument(); + * ``` + * * @public */ - export class TechDocsAddonTester { private options: TechDocsAddonTesterOptions = defaultOptions; private addons: ReactElement[]; + /** + * Get a TechDocsAddonTester instance for a given set of Addons. + */ static buildAddonsInTechDocs(addons: ReactElement[]) { return new TechDocsAddonTester(addons); } @@ -125,7 +143,10 @@ export class TechDocsAddonTester { this.addons = addons; } - withApis(apis: TechdocsAddonTesterApis) { + /** + * Provide mock API implementations if your Addon expects any. + */ + withApis(apis: TechdocsAddonTesterApis) { const refs = apis.map(([ref]) => ref); this.options.apis = this.options.apis .filter(([ref]) => !refs.includes(ref)) @@ -133,28 +154,46 @@ export class TechDocsAddonTester { return this; } + /** + * Provide mock HTML if your Addon expects it in the shadow DOM. + */ withDom(dom: ReactElement) { this.options.dom = dom; return this; } + /** + * Provide mock techdocs_metadata.json values if your Addon needs it. + */ withMetadata(metadata: Partial) { this.options.metadata = metadata; return this; } + /** + * Provide a mock entity if your Addon needs it. This also controls the base + * path at which the Addon is rendered. + */ withEntity(entity: Partial) { this.options.entity = entity; return this; } + /** + * Provide the TechDocs page path at which the Addon is rendered (e.g. the + * part of the path after the entity namespace/kind/name). + */ atPath(path: string) { this.options.path = path; return this; } + /** + * Return a fully configured and mocked TechDocs reader page within a test + * App instance, using the given Addon(s). + */ build() { - const apis: TechdocsAddonTesterApis = [ + const apis: TechdocsAddonTesterApis = [ [techdocsApiRef, techdocsApi], [techdocsStorageApiRef, techdocsStorageApi], [searchApiRef, searchApi], @@ -219,11 +258,19 @@ export class TechDocsAddonTester { }); } - // Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async - // act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit - // cleaner, since act doesn't return the result of the evaluated function. - // https://github.com/testing-library/react-testing-library/issues/281 - // https://github.com/facebook/react/pull/14853 + /** + * Render the Addon within a fully configured and mocked TechDocs reader. + * + * @remarks + * Components using useEffect to perform an asynchronous action (such as + * fetch) must be rendered within an async act call to properly get the final + * state, even with mocked responses. This utility method makes the signature + * a bit cleaner, since act doesn't return the result of the evaluated + * function. + * + * @see https://github.com/testing-library/react-testing-library/issues/281 + * @see https://github.com/facebook/react/pull/14853 + */ async renderWithEffects(): Promise< typeof screen & { shadowRoot: ShadowRoot | null } > { diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts index 915b027854..d458eeaba0 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts @@ -179,7 +179,18 @@ export class DefaultTechDocsCollatorFactory implements DocumentCollatorFactory { }, }, ); - const searchIndex = await searchIndexResponse.json(); + + // todo(@backstage/techdocs-core): remove Promise.race() when node-fetch is 3.x+ + // workaround for fetch().json() hanging in node-fetch@2.x.x, fixed in 3.x.x + // https://github.com/node-fetch/node-fetch/issues/665 + const searchIndex = await Promise.race([ + searchIndexResponse.json(), + new Promise((_resolve, reject) => { + setTimeout(() => { + reject('Could not parse JSON in 5 seconds.'); + }, 5000); + }), + ]); return searchIndex.docs.map((doc: MkSearchIndexDoc) => ({ title: unescape(doc.title), diff --git a/plugins/techdocs-module-addons-contrib/api-report.md b/plugins/techdocs-module-addons-contrib/api-report.md index 490b414141..efe88e2d5c 100644 --- a/plugins/techdocs-module-addons-contrib/api-report.md +++ b/plugins/techdocs-module-addons-contrib/api-report.md @@ -7,22 +7,25 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; +// @public +export const ExpandableNavigation: () => JSX.Element | null; + // @public export const ReportIssue: (props: ReportIssueProps) => JSX.Element | null; -// @public (undocumented) +// @public export type ReportIssueProps = { debounceTime?: number; templateBuilder?: ReportIssueTemplateBuilder; }; -// @public (undocumented) +// @public export type ReportIssueTemplate = { title: string; body: string; }; -// @public (undocumented) +// @public export type ReportIssueTemplateBuilder = ({ selection, }: { @@ -33,5 +36,5 @@ export type ReportIssueTemplateBuilder = ({ export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}>; // @public -export const TextSize: (props: unknown) => JSX.Element | null; +export const TextSize: () => JSX.Element | null; ``` diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 8a1801f0ba..074d12a505 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -43,6 +43,7 @@ "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", + "@react-hookz/web": "^13.0.0", "git-url-parse": "^11.6.0", "react-use": "^17.2.4" }, diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.test.tsx b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.test.tsx new file mode 100644 index 0000000000..3efc923145 --- /dev/null +++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.test.tsx @@ -0,0 +1,146 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TechDocsAddonTester } from '@backstage/plugin-techdocs-addons-test-utils'; + +import React from 'react'; +import { fireEvent, waitFor } from '@testing-library/react'; + +import { ExpandableNavigation } from '../plugin'; + +const mockNavWithSublevels = ( +
+ +
+); + +const mockNavWithoutSublevels = ( + +); + +describe('ExpandableNavigation', () => { + it('renders without exploding', async () => { + const { getByRole } = await TechDocsAddonTester.buildAddonsInTechDocs([ + , + ]) + .withDom(mockNavWithSublevels) + .renderWithEffects(); + + expect(getByRole('button', { name: 'expand-nav' })).toBeInTheDocument(); + }); + + it('expands and collapses navigation', async () => { + const { getByRole, shadowRoot } = + await TechDocsAddonTester.buildAddonsInTechDocs([ + , + ]) + .withDom(mockNavWithSublevels) + .renderWithEffects(); + + const toggles = + shadowRoot!.querySelectorAll('.md-toggle'); + + expect(toggles).toHaveLength(2); + toggles.forEach(item => { + expect(item).not.toBeChecked(); + }); + + const expandButton = getByRole('button', { name: 'expand-nav' }); + + fireEvent.click(expandButton); + + await waitFor(() => { + expect(getByRole('button', { name: 'collapse-nav' })).toBeInTheDocument(); + toggles.forEach(item => { + expect(item).toBeChecked(); + }); + }); + + const collapseButton = getByRole('button', { name: 'collapse-nav' }); + + fireEvent.click(collapseButton); + + await waitFor(() => { + toggles.forEach(item => { + expect(item).not.toBeChecked(); + }); + }); + }); + + it('does not render when navigation has no sublevels', async () => { + const { queryByRole } = await TechDocsAddonTester.buildAddonsInTechDocs([ + , + ]) + .withDom(mockNavWithoutSublevels) + .renderWithEffects(); + + expect( + queryByRole('button', { name: 'expand-nav' }), + ).not.toBeInTheDocument(); + }); +}); diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx new file mode 100644 index 0000000000..5ef76187e3 --- /dev/null +++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx @@ -0,0 +1,126 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect, useCallback, useState } from 'react'; +import { useLocalStorageValue } from '@react-hookz/web'; +import { Button, withStyles } from '@material-ui/core'; +import ChevronRightIcon from '@material-ui/icons/ChevronRight'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; + +import { useShadowRootElements } from '@backstage/plugin-techdocs-react'; + +const NESTED_LIST_TOGGLE = '.md-nav__item--nested .md-toggle'; + +const EXPANDABLE_NAVIGATION_LOCAL_STORAGE = + '@backstage/techdocs-addons/nav-expanded'; + +const StyledButton = withStyles({ + root: { + position: 'absolute', + left: '220px', + top: '19px', + padding: 0, + minWidth: 0, + }, +})(Button); + +const CollapsedIcon = withStyles({ + root: { + height: '20px', + width: '20px', + }, +})(ChevronRightIcon); + +const ExpandedIcon = withStyles({ + root: { + height: '20px', + width: '20px', + }, +})(ExpandMoreIcon); + +type expandableNavigationLocalStorage = { + expandAllNestedNavs: boolean; +}; + +/** + * Show expand/collapse navigation button next to site name in main + * navigation menu if documentation site has nested navigation. + */ +export const ExpandableNavigationAddon = () => { + const defaultValue = { expandAllNestedNavs: false }; + const [expanded, setExpanded] = + useLocalStorageValue( + EXPANDABLE_NAVIGATION_LOCAL_STORAGE, + defaultValue, + ); + const [hasNavSubLevels, setHasNavSubLevels] = useState(false); + + const [...checkboxToggles] = useShadowRootElements([ + NESTED_LIST_TOGGLE, + ]); + + const shouldToggle = useCallback( + (item: HTMLInputElement) => { + const isExpanded = item.checked; + const shouldExpand = expanded?.expandAllNestedNavs; + + // Is collapsed but should expand + if (shouldExpand && !isExpanded) { + return true; + } + + // Is expanded but should collapse + if (!shouldExpand && isExpanded) { + return true; + } + + return false; + }, + [expanded], + ); + + useEffect(() => { + // There is no nested navs + if (!checkboxToggles?.length) return; + + setHasNavSubLevels(true); + checkboxToggles.forEach(item => { + if (shouldToggle(item)) item.click(); + }); + }, [expanded, shouldToggle, checkboxToggles]); + + const handleState = () => { + setExpanded(prevState => ({ + expandAllNestedNavs: !prevState?.expandAllNestedNavs, + })); + }; + + return ( + <> + {hasNavSubLevels ? ( + + {expanded?.expandAllNestedNavs ? : } + + ) : null} + + ); +}; diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts new file mode 100644 index 0000000000..8f1c131d08 --- /dev/null +++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './ExpandableNavigation'; diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx index 68bde5c762..459fa1b65e 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { fireEvent, waitFor } from '@testing-library/react'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; -import { ReportIssue } from '..'; +import { ReportIssue } from '../plugin'; const byUrl = jest.fn(); diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx index 2fe8d604e6..c8caa5ddbc 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx @@ -49,10 +49,21 @@ type Style = { }; /** + * Props customizing the Addon. + * * @public */ export type ReportIssueProps = { + /** + * Number of milliseconds after a user highlights some text before the report + * issue link appears above the highlighted text. Defaults to 500ms. + */ debounceTime?: number; + + /** + * An optional function defining how a custom issue title and body should be + * constructed, given some selected text. + */ templateBuilder?: ReportIssueTemplateBuilder; }; diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/types.ts b/plugins/techdocs-module-addons-contrib/src/ReportIssue/types.ts index a4780535ca..0816b45d9d 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/types.ts +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/types.ts @@ -15,14 +15,26 @@ */ /** + * Properties for creating an issue in a remote issue tracker. + * * @public */ export type ReportIssueTemplate = { + /** + * The title of the issue. + */ title: string; + + /** + * The body or description of the issue. + */ body: string; }; /** + * A function for returning a custom issue template, given a selection of text + * on a TechDocs page. + * * @public */ export type ReportIssueTemplateBuilder = ({ diff --git a/plugins/techdocs-module-addons-contrib/src/TextSize/TextSize.test.tsx b/plugins/techdocs-module-addons-contrib/src/TextSize/TextSize.test.tsx index 282d54a0b6..6b4a055c2a 100644 --- a/plugins/techdocs-module-addons-contrib/src/TextSize/TextSize.test.tsx +++ b/plugins/techdocs-module-addons-contrib/src/TextSize/TextSize.test.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { fireEvent, waitFor } from '@testing-library/react'; -import { TextSize } from '..'; +import { TextSize } from '../plugin'; describe('TextSize', () => { it('renders without exploding', async () => { diff --git a/plugins/techdocs-module-addons-contrib/src/index.ts b/plugins/techdocs-module-addons-contrib/src/index.ts index e2e57b15d1..528afe5c0d 100644 --- a/plugins/techdocs-module-addons-contrib/src/index.ts +++ b/plugins/techdocs-module-addons-contrib/src/index.ts @@ -22,6 +22,7 @@ export { techdocsModuleAddonsContribPlugin, + ExpandableNavigation, ReportIssue, TextSize, } from './plugin'; diff --git a/plugins/techdocs-module-addons-contrib/src/plugin.ts b/plugins/techdocs-module-addons-contrib/src/plugin.ts index 0d7743da9e..6136f176d0 100644 --- a/plugins/techdocs-module-addons-contrib/src/plugin.ts +++ b/plugins/techdocs-module-addons-contrib/src/plugin.ts @@ -19,6 +19,7 @@ import { createTechDocsAddonExtension, TechDocsAddonLocations, } from '@backstage/plugin-techdocs-react'; +import { ExpandableNavigationAddon } from './ExpandableNavigation'; import { ReportIssueAddon, ReportIssueProps } from './ReportIssue'; import { TextSizeAddon } from './TextSize'; @@ -33,11 +34,122 @@ export const techdocsModuleAddonsContribPlugin = createPlugin({ }); /** - * TechDocs addon that lets you select text and open GitHub/Gitlab issues + * TechDocs addon that lets you expand/collapse the TechDocs main navigation + * and keep the preferred state in local storage. The addon will render as + * a button next to the site name if the documentation has nested navigation. + * + * @example + * Here's a simple example: + * ``` + * import { + * DefaultTechDocsHome, + * TechDocsIndexPage, + * TechDocsReaderPage, + * } from '@backstage/plugin-techdocs'; + * import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha'; + * import { ExpandableNavigation } from '@backstage/plugin-techdocs-module-addons-contrib'; + * + * + * const AppRoutes = () => { + * + * // other plugin routes + * }> + * + * + * } + * > + * + * + * + * + * ; + * }; + * ``` * * @public */ +export const ExpandableNavigation = techdocsModuleAddonsContribPlugin.provide( + createTechDocsAddonExtension({ + name: 'ExpandableNavigation', + location: TechDocsAddonLocations.PrimarySidebar, + component: ExpandableNavigationAddon, + }), +); + +/** + * TechDocs addon that lets you select text and open GitHub/Gitlab issues + * + * @remarks + * Before using it, you should set up an `edit_uri` for your pages as explained {@link https://backstage.io/docs/features/techdocs/faqs#is-it-possible-for-users-to-suggest-changes-or-provide-feedback-on-a-techdocs-page | here} and remember, it only works for Github or Gitlab. + * + * @example + * Here's a simple example: + * ``` + * import { + * DefaultTechDocsHome, + * TechDocsIndexPage, + * TechDocsReaderPage, + * } from '@backstage/plugin-techdocs'; + * import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; + * import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; + * + * + * const AppRoutes = () => { + * + * // other plugin routes + * }> + * + * + * } + * > + * + * + * + * + * ; + * }; + * ``` + * + * @example + * Here's an example with `debounceTime` and `templateBuilder` props: + * ``` + * import { + * DefaultTechDocsHome, + * TechDocsIndexPage, + * TechDocsReaderPage, + * } from '@backstage/plugin-techdocs'; + * import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; + * import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; + * + * const templateBuilder = ({ selection }: ReportIssueTemplateBuilder) => (({ + * title: 'Custom issue title', + * body: `Custom issue body: ${selection.toString()}` + * })) + * + * const AppRoutes = () => { + * + * // other plugin routes + * }> + * + * + * } + * > + * + * + * + * + * ; + * ``` + * @param props - Object that can optionally contain `debounceTime` and `templateBuilder` properties. + * @public + */ export const ReportIssue = techdocsModuleAddonsContribPlugin.provide( createTechDocsAddonExtension({ name: 'ReportIssue', @@ -60,7 +172,7 @@ export const ReportIssue = techdocsModuleAddonsContribPlugin.provide( * TechDocsIndexPage, * TechDocsReaderPage, * } from '@backstage/plugin-techdocs'; - * import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha'; + * import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; * import { TextSize } from '@backstage/plugin-techdocs-module-addons-contrib'; * * diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index d099f7351a..c584dec40c 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -219,7 +219,7 @@ export class TechdocsGenerator implements GeneratorBase { config: Config; scmIntegrations: ScmIntegrationRegistry; }); - static readonly defaultDockerImage = 'spotify/techdocs:v1.0.2'; + static readonly defaultDockerImage = 'spotify/techdocs:v1.0.3'; static fromConfig( config: Config, options: GeneratorOptions, diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index 41b17d3bc6..660b8e8cb5 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -53,7 +53,7 @@ export class TechdocsGenerator implements GeneratorBase { * The default docker image (and version) used to generate content. Public * and static so that techdocs-node consumers can use the same version. */ - public static readonly defaultDockerImage = 'spotify/techdocs:v1.0.2'; + public static readonly defaultDockerImage = 'spotify/techdocs:v1.0.3'; private readonly logger: Logger; private readonly containerRunner: ContainerRunner; private readonly options: GeneratorConfig; diff --git a/plugins/techdocs-react/api-report.md b/plugins/techdocs-react/api-report.md index d3803d6794..b3ee9168a6 100644 --- a/plugins/techdocs-react/api-report.md +++ b/plugins/techdocs-react/api-report.md @@ -14,21 +14,23 @@ import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { SetStateAction } from 'react'; -// @alpha +// @public +export function createTechDocsAddonExtension( + options: TechDocsAddonOptions, +): Extension<() => JSX.Element | null>; + +// @public export function createTechDocsAddonExtension( options: TechDocsAddonOptions, ): Extension<(props: TComponentProps) => JSX.Element | null>; -// @alpha (undocumented) -export const defaultTechDocsReaderPageValue: TechDocsReaderPageValue; - // @public export type SyncResult = 'cached' | 'updated'; -// @alpha +// @public export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; -// @alpha +// @public export const TechDocsAddonLocations: Readonly<{ readonly Header: 'Header'; readonly Subheader: 'Subheader'; @@ -38,14 +40,14 @@ export const TechDocsAddonLocations: Readonly<{ readonly Content: 'Content'; }>; -// @alpha +// @public export type TechDocsAddonOptions = { name: string; location: keyof typeof TechDocsAddonLocations; component: ComponentType; }; -// @alpha +// @public export const TechDocsAddons: React_2.ComponentType; // @public @@ -133,20 +135,20 @@ export interface TechDocsStorageApi { // @public export const techdocsStorageApiRef: ApiRef; -// @alpha +// @public export const useShadowRoot: () => ShadowRoot | undefined; -// @alpha +// @public export const useShadowRootElements: < TReturnedElement extends HTMLElement = HTMLElement, >( selectors: string[], ) => TReturnedElement[]; -// @alpha +// @public export const useShadowRootSelection: (wait?: number) => Selection | null; -// @alpha +// @public export const useTechDocsAddons: () => { renderComponentByName: (name: string) => JSX.Element | null; renderComponentsByLocation: ( @@ -154,6 +156,6 @@ export const useTechDocsAddons: () => { ) => (JSX.Element | null)[] | null; }; -// @alpha +// @public export const useTechDocsReaderPage: () => TechDocsReaderPageValue; ``` diff --git a/plugins/techdocs-react/src/addons.tsx b/plugins/techdocs-react/src/addons.tsx index 39d110bee3..ce5b3eb5cd 100644 --- a/plugins/techdocs-react/src/addons.tsx +++ b/plugins/techdocs-react/src/addons.tsx @@ -31,13 +31,13 @@ export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; /** * Marks the registry component. - * @alpha + * @public */ export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; /** * TechDocs Addon registry. - * @alpha + * @public */ export const TechDocsAddons: React.ComponentType = () => null; @@ -48,8 +48,24 @@ const getDataKeyByName = (name: string) => { }; /** - * Create a TechDocs addon. - * @alpha + * Create a TechDocs addon overload signature without props. + * @public + */ +export function createTechDocsAddonExtension( + options: TechDocsAddonOptions, +): Extension<() => JSX.Element | null>; + +/** + * Create a TechDocs addon overload signature with props. + * @public + */ +export function createTechDocsAddonExtension( + options: TechDocsAddonOptions, +): Extension<(props: TComponentProps) => JSX.Element | null>; + +/** + * Create a TechDocs addon implementation. + * @public */ export function createTechDocsAddonExtension( options: TechDocsAddonOptions, @@ -96,7 +112,7 @@ const getAllTechDocsAddonsData = (collection: ElementCollection) => { /** * hook to use addons in components - * @alpha + * @public */ export const useTechDocsAddons = () => { const node = useOutlet(); diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 67bf416818..4f2fa26164 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -66,10 +66,7 @@ export type TechDocsReaderPageValue = { onReady?: () => void; }; -/** - * @alpha - */ -export const defaultTechDocsReaderPageValue: TechDocsReaderPageValue = { +const defaultTechDocsReaderPageValue: TechDocsReaderPageValue = { title: '', subtitle: '', setTitle: () => {}, @@ -153,7 +150,7 @@ export const TechDocsReaderPageProvider = memo( /** * Hook used to get access to shared state between reader page components. - * @alpha + * @public */ export const useTechDocsReaderPage = () => { const versionedContext = useContext(TechDocsReaderPageContext); diff --git a/plugins/techdocs-react/src/hooks.ts b/plugins/techdocs-react/src/hooks.ts index cc141c9e15..560c548156 100644 --- a/plugins/techdocs-react/src/hooks.ts +++ b/plugins/techdocs-react/src/hooks.ts @@ -20,7 +20,7 @@ import { useTechDocsReaderPage } from './context'; /** * Hook for use within TechDocs addons that provides access to the underlying * shadow root of the current page, allowing the DOM within to be mutated. - * @alpha + * @public */ export const useShadowRoot = () => { const { shadowRoot } = useTechDocsReaderPage(); @@ -31,7 +31,7 @@ export const useShadowRoot = () => { * Convenience hook for use within TechDocs addons that provides access to * elements that match a given selector within the shadow root. * - * @alpha + * @public */ export const useShadowRootElements = < TReturnedElement extends HTMLElement = HTMLElement, @@ -58,7 +58,7 @@ const isValidSelection = (newSelection: Selection) => { /** * Hook for retreiving a selection within the ShadowRoot. - * @alpha + * @public */ export const useShadowRootSelection = (wait: number = 0) => { const shadowRoot = useShadowRoot(); diff --git a/plugins/techdocs-react/src/index.ts b/plugins/techdocs-react/src/index.ts index c1cc3a1791..d4de5f0d29 100644 --- a/plugins/techdocs-react/src/index.ts +++ b/plugins/techdocs-react/src/index.ts @@ -28,11 +28,7 @@ export { } from './addons'; export { techdocsApiRef, techdocsStorageApiRef } from './api'; export type { SyncResult, TechDocsApi, TechDocsStorageApi } from './api'; -export { - defaultTechDocsReaderPageValue, - TechDocsReaderPageProvider, - useTechDocsReaderPage, -} from './context'; +export { TechDocsReaderPageProvider, useTechDocsReaderPage } from './context'; export type { TechDocsReaderPageProviderProps, TechDocsReaderPageProviderRenderFunction, diff --git a/plugins/techdocs-react/src/types.ts b/plugins/techdocs-react/src/types.ts index e147cd1dd1..d1fcc91db0 100644 --- a/plugins/techdocs-react/src/types.ts +++ b/plugins/techdocs-react/src/types.ts @@ -38,7 +38,7 @@ export type TechDocsEntityMetadata = Entity & { /** * Locations for which TechDocs addons may be declared and rendered. - * @alpha + * @public */ export const TechDocsAddonLocations = Object.freeze({ /** @@ -108,7 +108,7 @@ export const TechDocsAddonLocations = Object.freeze({ /** * Options for creating a TechDocs addon. - * @alpha + * @public */ export type TechDocsAddonOptions = { name: string; diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 99ec9ff4ae..f080aa4e2d 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-techdocs +## 1.1.1-next.3 + +### Patch Changes + +- cc8ddd0979: revert dependency `event-source-polyfill` to `1.0.25` +- Updated dependencies + - @backstage/core-components@0.9.4-next.2 + ## 1.1.1-next.2 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 81911dac7d..439cac40c0 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.1.1-next.2", + "version": "1.1.1-next.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", "@backstage/config": "^1.0.1-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/integration": "^1.2.0-next.1", @@ -52,7 +52,7 @@ "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.10.0", "dompurify": "^2.2.9", - "event-source-polyfill": "1.0.26", + "event-source-polyfill": "1.0.25", "git-url-parse": "^11.6.0", "jss": "~10.8.2", "lodash": "^4.17.21", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx index fbab933571..7c76f75eff 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx @@ -32,7 +32,7 @@ import { TechDocsSearch } from '../../../search'; import { TechDocsStateIndicator } from '../TechDocsStateIndicator'; import { useTechDocsReaderDom } from './dom'; -import { withTechDocsReaderProvider } from './context'; +import { withTechDocsReaderProvider } from '../TechDocsReaderProvider'; const useStyles = makeStyles({ search: { diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index 7a373ab302..92bfbb2e14 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -28,7 +28,7 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { techdocsStorageApiRef } from '@backstage/plugin-techdocs-react'; -import { useTechDocsReader } from './context'; +import { useTechDocsReader } from '../TechDocsReaderProvider'; import { addBaseUrl, @@ -58,14 +58,6 @@ const headings: TypographyHeadingsKeys[] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; * Hook that encapsulates the behavior of getting raw HTML and applying * transforms to it in order to make it function at a basic level in the * Backstage UI. - * - * Note: this hook is currently being exported so that we can rapidly iterate - * on alternative implementations that extend core functionality. - * There is no guarantee that this hook will continue to be exported by the - * package in the future! - * - * todo: Make public or stop exporting (see others: "altReaderExperiments") - * @internal */ export const useTechDocsReaderDom = ( entityRef: CompoundEntityRef, diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/index.ts b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/index.ts index a7ea76a5d6..b0e2ff856a 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/index.ts +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/index.ts @@ -16,5 +16,3 @@ export { TechDocsReaderPageContent, Reader } from './TechDocsReaderPageContent'; export type { TechDocsReaderPageContentProps } from './TechDocsReaderPageContent'; -export * from './context'; -export * from './dom'; diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/context.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderProvider.tsx similarity index 73% rename from plugins/techdocs/src/reader/components/TechDocsReaderPageContent/context.tsx rename to plugins/techdocs/src/reader/components/TechDocsReaderProvider.tsx index 5779ade90c..8ddc4cad69 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/context.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderProvider.tsx @@ -23,20 +23,10 @@ import React, { import { useParams } from 'react-router-dom'; import { useTechDocsReaderPage } from '@backstage/plugin-techdocs-react'; -import { useReaderState, ReaderState } from '../useReaderState'; +import { useReaderState, ReaderState } from './useReaderState'; const TechDocsReaderContext = createContext({} as ReaderState); -/** - * Note: this hook is currently being exported so that we can rapidly - * iterate on alternative implementations that extend core - * functionality. There is no guarantee that this hook will continue to be - * exported by the package in the future! - * - * todo: Make public or stop exporting (ctrl+f "altReaderExperiments") - * @internal - */ - export const useTechDocsReader = () => useContext(TechDocsReaderContext); /** @@ -73,15 +63,6 @@ export const TechDocsReaderProvider = ({ ); }; -/** - * Note: this HOC is currently being exported so that we can rapidly - * iterate on alternative implementations that extend core - * functionality. There is no guarantee that this HOC will continue to be - * exported by the package in the future! - * - * todo: Make public or stop exporting (ctrl+f "altReaderExperiments") - * @internal - */ export const withTechDocsReaderProvider = (Component: ComponentType) => (props: T) => diff --git a/plugins/techdocs/src/reader/components/TechDocsStateIndicator.tsx b/plugins/techdocs/src/reader/components/TechDocsStateIndicator.tsx index 93694280d7..6967356194 100644 --- a/plugins/techdocs/src/reader/components/TechDocsStateIndicator.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsStateIndicator.tsx @@ -21,7 +21,7 @@ import { Alert } from '@material-ui/lab'; import { TechDocsBuildLogs } from './TechDocsBuildLogs'; import { TechDocsNotFound } from './TechDocsNotFound'; -import { useTechDocsReader } from './TechDocsReaderPageContent'; +import { useTechDocsReader } from './TechDocsReaderProvider'; const useStyles = makeStyles(theme => ({ root: { @@ -35,15 +35,6 @@ const useStyles = makeStyles(theme => ({ }, })); -/** - * Note: this component is currently being exported so that we can rapidly - * iterate on alternative implementations that extend core - * functionality. There is no guarantee that this component will continue to be - * exported by the package in the future! - * - * todo: Make public or stop exporting (ctrl+f "altReaderExperiments") - * @internal - */ export const TechDocsStateIndicator = () => { let StateAlert: JSX.Element | null = null; const classes = useStyles(); diff --git a/plugins/techdocs/src/reader/components/index.ts b/plugins/techdocs/src/reader/components/index.ts index 406d623bda..f063501814 100644 --- a/plugins/techdocs/src/reader/components/index.ts +++ b/plugins/techdocs/src/reader/components/index.ts @@ -14,6 +14,11 @@ * limitations under the License. */ +export { TechDocsReaderProvider } from './TechDocsReaderProvider'; +export type { + TechDocsReaderProviderRenderFunction, + TechDocsReaderProviderProps, +} from './TechDocsReaderProvider'; export type { TechDocsReaderPageProps, TechDocsReaderLayoutProps, @@ -22,5 +27,4 @@ export { TechDocsReaderLayout } from './TechDocsReaderPage'; export * from './TechDocsReaderPageHeader'; export * from './TechDocsReaderPageContent'; export * from './TechDocsReaderPageSubheader'; -export * from './TechDocsStateIndicator'; export type { ReaderState, ContentStateTypes } from './useReaderState'; diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 986b7b03fa..1185eb6b74 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.0.2-next.0", - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/plugin-catalog-react": "^1.1.0-next.2", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 044d6f5536..6461ba753b 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/theme": "^0.2.15", "@material-ui/core": "^4.12.2", diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 3ab1dfe512..f7396220d7 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.4-next.1", + "@backstage/core-components": "^0.9.4-next.2", "@backstage/core-plugin-api": "^1.0.2-next.1", "@backstage/errors": "^1.0.0", "@backstage/theme": "^0.2.15", diff --git a/storybook/.storybook/main.js b/storybook/.storybook/main.js index 8ed4949cf3..f493bd2de6 100644 --- a/storybook/.storybook/main.js +++ b/storybook/.storybook/main.js @@ -32,6 +32,7 @@ module.exports = ({ args }) => { return { stories, addons: [ + '@storybook/addon-controls', '@storybook/addon-a11y', '@storybook/addon-actions', '@storybook/addon-links', diff --git a/storybook/package.json b/storybook/package.json index 9a9c7d4a8c..eafe73a991 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -9,14 +9,15 @@ }, "dependencies": { "@sucrase/webpack-loader": "^2.0.0", - "sucrase": "^3.21.0", "react": "^17.0.2", + "react-dom": "^17.0.2", "react-hot-loader": "^4.13.0", - "react-dom": "^17.0.2" + "sucrase": "^3.21.0" }, "devDependencies": { "@storybook/addon-a11y": "^6.4.21", "@storybook/addon-actions": "^6.4.21", + "@storybook/addon-controls": "^6.4.22", "@storybook/addon-links": "^6.4.21", "@storybook/addon-storysource": "^6.4.21", "@storybook/addons": "^6.4.21", @@ -24,9 +25,9 @@ "storybook-dark-mode": "^1.0.9" }, "peerDependencies": { - "@backstage/theme": "link:../packages/theme", - "@backstage/test-utils": "link:../packages/test-utils", "@backstage/core-app-api": "link:../packages/core-app-api", - "@backstage/core-plugin-api": "link:../packages/core-plugin-api" + "@backstage/core-plugin-api": "link:../packages/core-plugin-api", + "@backstage/test-utils": "link:../packages/test-utils", + "@backstage/theme": "link:../packages/theme" } } diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 4660d682bc..8c6380c291 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -1381,6 +1381,24 @@ util-deprecate "^1.0.2" uuid-browser "^3.1.0" +"@storybook/addon-controls@^6.4.22": + version "6.4.22" + resolved "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-6.4.22.tgz#42c7f426eb7ba6d335e8e14369d6d13401878665" + integrity sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ== + dependencies: + "@storybook/addons" "6.4.22" + "@storybook/api" "6.4.22" + "@storybook/client-logger" "6.4.22" + "@storybook/components" "6.4.22" + "@storybook/core-common" "6.4.22" + "@storybook/csf" "0.0.2--canary.87bc651.0" + "@storybook/node-logger" "6.4.22" + "@storybook/store" "6.4.22" + "@storybook/theming" "6.4.22" + core-js "^3.8.2" + lodash "^4.17.21" + ts-dedent "^2.0.0" + "@storybook/addon-links@^6.4.21": version "6.4.22" resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.22.tgz#c0ed9e9ef6505cf1562e1476bbc5064c82dadbe2" diff --git a/yarn.lock b/yarn.lock index 777d918095..02fd7077c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2245,10 +2245,10 @@ teeny-request "^7.1.3" xdg-basedir "^4.0.0" -"@graphiql/toolkit@^0.4.3": - version "0.4.3" - resolved "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.4.3.tgz#2653d045693d902f7faaf87b9047e8786397ec48" - integrity sha512-L0l6BezvTXmWZhtdmZxirhYwKzcZToAciQY0A13KRAWSpJ9bb/ZdkBpcz3fOXrsjuJHf0wBr6Vk9kztJ6lV7uA== +"@graphiql/toolkit@^0.4.4": + version "0.4.5" + resolved "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.4.5.tgz#9fb5020444712562eae9581724695c235f610836" + integrity sha512-QXuuMSSK/0GfBS7tltrGZdyhIvm6oe9TK4VW9pfa8dALYttpzyJ64Q4Sx9I1Ng++yOMJWziM/ksa043zkNHsjQ== dependencies: "@n1ru4l/push-pull-async-iterable-iterator" "^3.1.0" meros "^1.1.4" @@ -3295,11 +3295,11 @@ integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== "@keyv/redis@^2.2.3": - version "2.3.4" - resolved "https://registry.npmjs.org/@keyv/redis/-/redis-2.3.4.tgz#441b7fd1e27d2c361ae0180afd9182a45ac6ee68" - integrity sha512-9DqSKV2v5nEcEJa6WajOiWw4GX1rE07Z2oNWaE4XjfPHWLvG46+uOlF0b3Xa5WBaExkWVc7bo5pLAOSK7lAaew== + version "2.3.5" + resolved "https://registry.npmjs.org/@keyv/redis/-/redis-2.3.5.tgz#8ff4fecf9b5520cac2a346e6216db59474df3385" + integrity sha512-dO9sn1HEPVkh1b7Cn/jcLyi7sDFKmnGQIaXw4wTIhJzkwcev24CffvEU26B+KRUNBu/2PgNVNRfFmEpy1smb4w== dependencies: - ioredis "^5.0.3" + ioredis "^5.0.4" "@kubernetes/client-node@^0.16.0": version "0.16.3" @@ -4200,9 +4200,9 @@ react-is "^16.8.0 || ^17.0.0" "@maxim_mazurok/gapi.client.calendar@^3.0.20220408": - version "3.0.20220429" - resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220429.tgz#ccd5116bd5222a586782e83c4f1370179c600a2b" - integrity sha512-vzjnM+bRo2Heq8BuaWEQUxnB+yi7KmCqs6YfgZITp/84r3IKRLQuu5vAiaHu37kOYKKswRVJ+K5vBU6B742jag== + version "3.0.20220505" + resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220505.tgz#14a72876308481cb97a2ffa859543b1fa0ee258e" + integrity sha512-ZzsJdybuX/RvcDU8eF7XCyHdKYuHU6Z12326hB2+f4IWkMrDTQCayu05cRXZEuvP2YwoPm8gglPpV+flYk1d3g== dependencies: "@types/gapi.client" "*" @@ -4982,9 +4982,9 @@ zustand "3.6.9" "@roadiehq/backstage-plugin-github-pull-requests@^2.0.0": - version "2.1.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.1.1.tgz#90bc2e82c47ddf5fe40063ddcfff9efdb464f046" - integrity sha512-/855fB7F0Ss4h7iTayBu/SVbWLM5iw3401ER5uWf1IoSpXorJECEW0lfzroJtWMGse6LfNfbuWqTKnp2vTSosg== + version "2.1.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.1.2.tgz#1c8289679bb109a70c30b5ba090ea7d751553764" + integrity sha512-VXv1D1JhifX0B9nukxFa61MyXouPTXEYkeNwYB+Y3e0VfoPEGzAeE/Ub23rP8aVcYsbuyCA+6u/HQsrw6Vgpxw== dependencies: "@backstage/catalog-model" "^1.0.0" "@backstage/core-components" "^0.9.0" @@ -5407,17 +5407,10 @@ "@testing-library/dom" "^8.0.0" "@types/react-dom" "<18.0.0" -"@testing-library/user-event@^13.1.8": - version "13.5.0" - resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" - integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== - dependencies: - "@babel/runtime" "^7.12.5" - "@testing-library/user-event@^14.0.0": - version "14.1.1" - resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.1.1.tgz#e1ff6118896e4b22af31e5ea2f9da956adde23d8" - integrity sha512-XrjH/iEUqNl9lF2HX9YhPNV7Amntkcnpw0Bo1KkRzowNDcgSN9i0nm4Q8Oi5wupgdfPaJNMAWa61A+voD6Kmwg== + version "14.2.0" + resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.2.0.tgz#8293560f8f80a00383d6c755ec3e0b918acb1683" + integrity sha512-+hIlG4nJS6ivZrKnOP7OGsDu9Fxmryj9vCl8x0ZINtTJcCHs2zLsYif5GzuRiBF2ck5GZG2aQr7Msg+EHlnYVQ== "@tokenizer/token@^0.3.0": version "0.3.0" @@ -6291,9 +6284,9 @@ integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/node@^16.0.0", "@types/node@^16.11.26", "@types/node@^16.9.2": - version "16.11.33" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.33.tgz#566713b1b626f781c5c58fe3531307283e00720c" - integrity sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA== + version "16.11.35" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.35.tgz#6642bdce5b5cee23314b91a7c069981c6bd68791" + integrity sha512-QXu45LyepgnhUfnIAj/FyT4uM87ug5KpIrgXfQtUPNAlx8w5hmd8z8emqCLNvG11QkpRSCG9Qg2buMxvqfjfsQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -6417,9 +6410,9 @@ integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== "@types/react-dom@*", "@types/react-dom@<18.0.0", "@types/react-dom@^17": - version "17.0.16" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.16.tgz#7caba93cf2806c51e64d620d8dff4bae57e06cc4" - integrity sha512-DWcXf8EbMrO/gWnQU7Z88Ws/p16qxGpPyjTKTpmBSFKeE+HveVubqGO1CVK7FrwlWD5MuOcvh8gtd0/XO38NdQ== + version "17.0.17" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" + integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== dependencies: "@types/react" "^17" @@ -6483,9 +6476,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^16.13.1 || ^17.0.0", "@types/react@^17": - version "17.0.44" - resolved "https://registry.npmjs.org/@types/react/-/react-17.0.44.tgz#c3714bd34dd551ab20b8015d9d0dbec812a51ec7" - integrity sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g== + version "17.0.45" + resolved "https://registry.npmjs.org/@types/react/-/react-17.0.45.tgz#9b3d5b661fd26365fefef0e766a1c6c30ccf7b3f" + integrity sha512-YfhQ22Lah2e3CHPsb93tRwIGNiSwkuz1/blk4e6QrWS0jQzCSNbGLtOEYhPg02W0yGTTmpajp7dCTbBAMN3qsg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -6692,9 +6685,9 @@ "@types/node" "*" "@types/swagger-ui-react@^4.1.1": - version "4.1.1" - resolved "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-4.1.1.tgz#6ae70f5b966941eb6655d79d1114d9b9ef69a980" - integrity sha512-tZqX/nShvNqtJ7WAfwOK7mphK1jqmEre4mUJh+R1RyCFVODsMTG4My2nqjXpSm8NfhVGmbFH3giD17AXmgsaJw== + version "4.11.0" + resolved "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-4.11.0.tgz#3ac84bc8e2f6e57b9ff4533ec31934f697e1a2c4" + integrity sha512-WPMR+GWbLd7zvY/uOTGzGzP44zK2rIZSnU00+pDR2YANnEV6/qj0kqYfdSY1Vk6qdvI7dR0Tx8JEMgUUrUQDjw== dependencies: "@types/react" "*" @@ -6866,13 +6859,13 @@ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^5.9.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz#7b52a0de2e664044f28b36419210aea4ab619e2a" - integrity sha512-YCiy5PUzpAeOPGQ7VSGDEY2NeYUV1B0swde2e0HzokRsHBYjSdF6DZ51OuRZxVPHx0032lXGLvOMls91D8FXlg== + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.23.0.tgz#bc4cbcf91fbbcc2e47e534774781b82ae25cc3d8" + integrity sha512-hEcSmG4XodSLiAp1uxv/OQSGsDY6QN3TcRU32gANp+19wGE1QQZLRS8/GV58VRUoXhnkuJ3ZxNQ3T6Z6zM59DA== dependencies: - "@typescript-eslint/scope-manager" "5.22.0" - "@typescript-eslint/type-utils" "5.22.0" - "@typescript-eslint/utils" "5.22.0" + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/type-utils" "5.23.0" + "@typescript-eslint/utils" "5.23.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -6893,13 +6886,13 @@ eslint-utils "^3.0.0" "@typescript-eslint/parser@^5.9.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.22.0.tgz#7bedf8784ef0d5d60567c5ba4ce162460e70c178" - integrity sha512-piwC4krUpRDqPaPbFaycN70KCP87+PC5WZmrWs+DlVOxxmF+zI6b6hETv7Quy4s9wbkV16ikMeZgXsvzwI3icQ== + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz#443778e1afc9a8ff180f91b5e260ac3bec5e2de1" + integrity sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw== dependencies: - "@typescript-eslint/scope-manager" "5.22.0" - "@typescript-eslint/types" "5.22.0" - "@typescript-eslint/typescript-estree" "5.22.0" + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/typescript-estree" "5.23.0" debug "^4.3.2" "@typescript-eslint/scope-manager@5.20.0": @@ -6910,13 +6903,13 @@ "@typescript-eslint/types" "5.20.0" "@typescript-eslint/visitor-keys" "5.20.0" -"@typescript-eslint/scope-manager@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.22.0.tgz#590865f244ebe6e46dc3e9cab7976fc2afa8af24" - integrity sha512-yA9G5NJgV5esANJCO0oF15MkBO20mIskbZ8ijfmlKIvQKg0ynVKfHZ15/nhAJN5m8Jn3X5qkwriQCiUntC9AbA== +"@typescript-eslint/scope-manager@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz#4305e61c2c8e3cfa3787d30f54e79430cc17ce1b" + integrity sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw== dependencies: - "@typescript-eslint/types" "5.22.0" - "@typescript-eslint/visitor-keys" "5.22.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/visitor-keys" "5.23.0" "@typescript-eslint/scope-manager@5.9.0": version "5.9.0" @@ -6926,12 +6919,12 @@ "@typescript-eslint/types" "5.9.0" "@typescript-eslint/visitor-keys" "5.9.0" -"@typescript-eslint/type-utils@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.22.0.tgz#0c0e93b34210e334fbe1bcb7250c470f4a537c19" - integrity sha512-iqfLZIsZhK2OEJ4cQ01xOq3NaCuG5FQRKyHicA3xhZxMgaxQazLUHbH/B2k9y5i7l3+o+B5ND9Mf1AWETeMISA== +"@typescript-eslint/type-utils@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.23.0.tgz#f852252f2fc27620d5bb279d8fed2a13d2e3685e" + integrity sha512-iuI05JsJl/SUnOTXA9f4oI+/4qS/Zcgk+s2ir+lRmXI+80D8GaGwoUqs4p+X+4AxDolPpEpVUdlEH4ADxFy4gw== dependencies: - "@typescript-eslint/utils" "5.22.0" + "@typescript-eslint/utils" "5.23.0" debug "^4.3.2" tsutils "^3.21.0" @@ -6940,10 +6933,10 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz#fa39c3c2aa786568302318f1cb51fcf64258c20c" integrity sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg== -"@typescript-eslint/types@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.22.0.tgz#50a4266e457a5d4c4b87ac31903b28b06b2c3ed0" - integrity sha512-T7owcXW4l0v7NTijmjGWwWf/1JqdlWiBzPqzAWhobxft0SiEvMJB56QXmeCQjrPuM8zEfGUKyPQr/L8+cFUBLw== +"@typescript-eslint/types@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz#8733de0f58ae0ed318dbdd8f09868cdbf9f9ad09" + integrity sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw== "@typescript-eslint/types@5.9.0": version "5.9.0" @@ -6963,13 +6956,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.22.0.tgz#e2116fd644c3e2fda7f4395158cddd38c0c6df97" - integrity sha512-EyBEQxvNjg80yinGE2xdhpDYm41so/1kOItl0qrjIiJ1kX/L/L8WWGmJg8ni6eG3DwqmOzDqOhe6763bF92nOw== +"@typescript-eslint/typescript-estree@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz#dca5f10a0a85226db0796e8ad86addc9aee52065" + integrity sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg== dependencies: - "@typescript-eslint/types" "5.22.0" - "@typescript-eslint/visitor-keys" "5.22.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/visitor-keys" "5.23.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -6989,15 +6982,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.22.0.tgz#1f2c4897e2cf7e44443c848a13c60407861babd8" - integrity sha512-HodsGb037iobrWSUMS7QH6Hl1kppikjA1ELiJlNSTYf/UdMEwzgj0WIp+lBNb6WZ3zTwb0tEz51j0Wee3iJ3wQ== +"@typescript-eslint/utils@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.23.0.tgz#4691c3d1b414da2c53d8943310df36ab1c50648a" + integrity sha512-dbgaKN21drqpkbbedGMNPCtRPZo1IOUr5EI9Jrrh99r5UW5Q0dz46RKXeSBoPV+56R6dFKpbrdhgUNSJsDDRZA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.22.0" - "@typescript-eslint/types" "5.22.0" - "@typescript-eslint/typescript-estree" "5.22.0" + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/typescript-estree" "5.23.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -7021,12 +7014,12 @@ "@typescript-eslint/types" "5.20.0" eslint-visitor-keys "^3.0.0" -"@typescript-eslint/visitor-keys@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.22.0.tgz#f49c0ce406944ffa331a1cfabeed451ea4d0909c" - integrity sha512-DbgTqn2Dv5RFWluG88tn0pP6Ex0ROF+dpDO1TNNZdRtLjUr6bdznjA6f/qNqJLjd2PgguAES2Zgxh/JzwzETDg== +"@typescript-eslint/visitor-keys@5.23.0": + version "5.23.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz#057c60a7ca64667a39f991473059377a8067c87b" + integrity sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg== dependencies: - "@typescript-eslint/types" "5.22.0" + "@typescript-eslint/types" "5.23.0" eslint-visitor-keys "^3.0.0" "@typescript-eslint/visitor-keys@5.9.0": @@ -7921,9 +7914,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1130.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1130.0.tgz#3aeeceaf1cfe82a8400295e7c2c6642a16a6a4fc" - integrity sha512-bkLXuOpHphKvaMAbbmqaHQtYsGICmoyEJdLlNOTCq7dH0uKxARcZEj01ebCifsJJ/fOrPt8EbNUHPu4/DOueDA== + version "2.1133.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1133.0.tgz#db530faaa8dbe98503fd600b4e95efdd1c3996c7" + integrity sha512-TK7lcDxkrAc15Lmx030u4Wn3P798oxBVs79DBsD8+cZcW5Y8Gvat+evIZpkDoqh8YsfegvlI2jFg4ECQxKYPVA== dependencies: buffer "4.9.2" events "1.1.1" @@ -9512,10 +9505,10 @@ component-inherit@0.0.3: resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= -compress-brotli@^1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.6.tgz#64bd6f21f4f3e9841dbac392f4c29218caf5e9d9" - integrity sha512-au99/GqZtUtiCBliqLFbWlhnCxn+XSYjwZ77q6mKN4La4qOXDoLVPZ50iXr0WmAyMxl8yqoq3Yq4OeQNPPkyeQ== +compress-brotli@^1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz#0c0a60c97a989145314ec381e84e26682e7b38db" + integrity sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ== dependencies: "@types/json-buffer" "~3.0.0" json-buffer "~3.0.1" @@ -9779,16 +9772,16 @@ cookie@0.4.1: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +cookie@0.4.2, cookie@^0.4.1, cookie@^0.4.2, cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + cookie@0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookie@^0.4.1, cookie@^0.4.2, cookie@~0.4.1: - version "0.4.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - cookiejar@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" @@ -9825,9 +9818,9 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.10: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.4.1, core-js@^3.6.5: - version "3.22.4" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.4.tgz#f4b3f108d45736935aa028444a69397e40d8c531" - integrity sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w== + version "3.22.5" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.5.tgz#a5f5a58e663d5c0ebb4e680cd7be37536fb2a9cf" + integrity sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -10273,9 +10266,9 @@ cypress-plugin-snapshots@^1.4.4: unidiff "1.0.2" cypress@^9.5.0: - version "9.6.0" - resolved "https://registry.npmjs.org/cypress/-/cypress-9.6.0.tgz#84473b3362255fa8f5e627a596e58575c9e5320f" - integrity sha512-nNwt9eBQmSENamwa8LxvggXksfyzpyYaQ7lNBLgks3XZ6dPE/6BCQFBzeAyAPt/bNXfH3tKPkAyhiAZPYkWoEg== + version "9.6.1" + resolved "https://registry.npmjs.org/cypress/-/cypress-9.6.1.tgz#a7d6b5a53325b3dc4960181f5800a5ade0f085eb" + integrity sha512-ECzmV7pJSkk+NuAhEw6C3D+RIRATkSb2VAHXDY6qGZbca/F9mv5pPsj2LO6Ty6oIFVBTrwCyL9agl28MtJMe2g== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -10917,10 +10910,10 @@ detect-port-alt@^1.1.6: address "^1.0.1" debug "^2.6.0" -devtools-protocol@0.0.981744: - version "0.0.981744" - resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz#9960da0370284577d46c28979a0b32651022bacf" - integrity sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg== +devtools-protocol@0.0.982423: + version "0.0.982423" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.982423.tgz#39ac3791d4c5b90ebb416d4384663b7b0cc44154" + integrity sha512-FnVW2nDbjGNw1uD/JRC+9U5768W7e1TfUwqbDTcSsAu1jXFjITSX8w3rkW5FEpHRMPPGpvNSmO1pOpqByiWscA== dezalgo@1.0.3, dezalgo@^1.0.0: version "1.0.3" @@ -11115,9 +11108,9 @@ dompurify@=2.3.3: integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== dompurify@^2.2.7, dompurify@^2.2.9, dompurify@^2.3.6: - version "2.3.6" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875" - integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg== + version "2.3.8" + resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f" + integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw== domutils@^2.5.2, domutils@^2.6.0: version "2.8.0" @@ -11361,10 +11354,10 @@ engine.io@~3.5.0: engine.io-parser "~2.2.0" ws "~7.4.2" -enhanced-resolve@^5.9.2: - version "5.9.2" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" - integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== +enhanced-resolve@^5.9.3: + version "5.9.3" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" + integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -11475,75 +11468,75 @@ es6-error@^4.1.1: resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz#5b94a1306df31d55055f64a62ff6b763a47b7f64" - integrity sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw== +esbuild-android-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.39.tgz#09f12a372eed9743fd77ff6d889ac14f7b340c21" + integrity sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ== -esbuild-android-arm64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz#78acc80773d16007de5219ccce544c036abd50b8" - integrity sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA== +esbuild-android-arm64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.39.tgz#f608d00ea03fe26f3b1ab92a30f99220390f3071" + integrity sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA== -esbuild-darwin-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz#e02b1291f629ebdc2aa46fabfacc9aa28ff6aa46" - integrity sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA== +esbuild-darwin-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz#31528daa75b4c9317721ede344195163fae3e041" + integrity sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g== -esbuild-darwin-arm64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz#01eb6650ec010b18c990e443a6abcca1d71290a9" - integrity sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ== +esbuild-darwin-arm64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.39.tgz#247f770d86d90a215fa194f24f90e30a0bd97245" + integrity sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw== -esbuild-freebsd-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz#790b8786729d4aac7be17648f9ea8e0e16475b5e" - integrity sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig== +esbuild-freebsd-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.39.tgz#479414d294905055eb396ebe455ed42213284ee0" + integrity sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ== -esbuild-freebsd-arm64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz#b66340ab28c09c1098e6d9d8ff656db47d7211e6" - integrity sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ== +esbuild-freebsd-arm64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.39.tgz#cedeb10357c88533615921ae767a67dc870a474c" + integrity sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg== -esbuild-linux-32@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz#7927f950986fd39f0ff319e92839455912b67f70" - integrity sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g== +esbuild-linux-32@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.39.tgz#d9f008c4322d771f3958f59c1eee5a05cdf92485" + integrity sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg== -esbuild-linux-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz#4893d07b229d9cfe34a2b3ce586399e73c3ac519" - integrity sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q== +esbuild-linux-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.39.tgz#ba58d7f66858913aeb1ab5c6bde1bbd824731795" + integrity sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ== -esbuild-linux-arm64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz#8442402e37d0b8ae946ac616784d9c1a2041056a" - integrity sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA== +esbuild-linux-arm64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.39.tgz#708785a30072702b5b1c16b65cf9c25c51202529" + integrity sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ== -esbuild-linux-arm@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz#d5dbf32d38b7f79be0ec6b5fb2f9251fd9066986" - integrity sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA== +esbuild-linux-arm@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.39.tgz#4e8b5deaa7ab60d0d28fab131244ef82b40684f4" + integrity sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ== -esbuild-linux-mips64le@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz#95081e42f698bbe35d8ccee0e3a237594b337eb5" - integrity sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ== +esbuild-linux-mips64le@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.39.tgz#6f3bf3023f711084e5a1e8190487d2020f39f0f7" + integrity sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw== -esbuild-linux-ppc64le@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz#dceb0a1b186f5df679618882a7990bd422089b47" - integrity sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q== +esbuild-linux-ppc64le@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.39.tgz#900e718a4ea3f6aedde8424828eeefdd4b48d4b9" + integrity sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ== -esbuild-linux-riscv64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz#61fb8edb75f475f9208c4a93ab2bfab63821afd2" - integrity sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ== +esbuild-linux-riscv64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.39.tgz#dcbff622fa37047a75d2ff7a1d8d2949d80277e4" + integrity sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA== -esbuild-linux-s390x@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz#34c7126a4937406bf6a5e69100185fd702d12fe0" - integrity sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ== +esbuild-linux-s390x@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.39.tgz#3f725a7945b419406c99d93744b28552561dcdfd" + integrity sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA== esbuild-loader@^2.18.0: version "2.18.0" @@ -11557,61 +11550,61 @@ esbuild-loader@^2.18.0: tapable "^2.2.0" webpack-sources "^2.2.0" -esbuild-netbsd-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz#322ea9937d9e529183ee281c7996b93eb38a5d95" - integrity sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q== +esbuild-netbsd-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.39.tgz#e10e40b6a765798b90d4eb85901cc85c8b7ff85e" + integrity sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA== -esbuild-openbsd-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz#1ca29bb7a2bf09592dcc26afdb45108f08a2cdbd" - integrity sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ== +esbuild-openbsd-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.39.tgz#935ec143f75ce10bd9cdb1c87fee00287eb0edbc" + integrity sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA== -esbuild-sunos-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz#c9446f7d8ebf45093e7bb0e7045506a88540019b" - integrity sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA== +esbuild-sunos-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.39.tgz#0e7aa82b022a2e6d55b0646738b2582c2d72c3c0" + integrity sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg== -esbuild-windows-32@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz#f8e9b4602fd0ccbd48e5c8d117ec0ba4040f2ad1" - integrity sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw== +esbuild-windows-32@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.39.tgz#3f1538241f31b538545f4b5841b248cac260fa35" + integrity sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q== -esbuild-windows-64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz#280f58e69f78535f470905ce3e43db1746518107" - integrity sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw== +esbuild-windows-64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.39.tgz#b100c59f96d3c2da2e796e42fee4900d755d3e03" + integrity sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow== -esbuild-windows-arm64@0.14.38: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz#d97e9ac0f95a4c236d9173fa9f86c983d6a53f54" - integrity sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw== +esbuild-windows-arm64@0.14.39: + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.39.tgz#00268517e665b33c89778d61f144e4256b39f631" + integrity sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA== esbuild@^0.14.1, esbuild@^0.14.10, esbuild@^0.14.6: - version "0.14.38" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz#99526b778cd9f35532955e26e1709a16cca2fb30" - integrity sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA== + version "0.14.39" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz#c926b2259fe6f6d3a94f528fb42e103c5a6d909a" + integrity sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ== optionalDependencies: - esbuild-android-64 "0.14.38" - esbuild-android-arm64 "0.14.38" - esbuild-darwin-64 "0.14.38" - esbuild-darwin-arm64 "0.14.38" - esbuild-freebsd-64 "0.14.38" - esbuild-freebsd-arm64 "0.14.38" - esbuild-linux-32 "0.14.38" - esbuild-linux-64 "0.14.38" - esbuild-linux-arm "0.14.38" - esbuild-linux-arm64 "0.14.38" - esbuild-linux-mips64le "0.14.38" - esbuild-linux-ppc64le "0.14.38" - esbuild-linux-riscv64 "0.14.38" - esbuild-linux-s390x "0.14.38" - esbuild-netbsd-64 "0.14.38" - esbuild-openbsd-64 "0.14.38" - esbuild-sunos-64 "0.14.38" - esbuild-windows-32 "0.14.38" - esbuild-windows-64 "0.14.38" - esbuild-windows-arm64 "0.14.38" + esbuild-android-64 "0.14.39" + esbuild-android-arm64 "0.14.39" + esbuild-darwin-64 "0.14.39" + esbuild-darwin-arm64 "0.14.39" + esbuild-freebsd-64 "0.14.39" + esbuild-freebsd-arm64 "0.14.39" + esbuild-linux-32 "0.14.39" + esbuild-linux-64 "0.14.39" + esbuild-linux-arm "0.14.39" + esbuild-linux-arm64 "0.14.39" + esbuild-linux-mips64le "0.14.39" + esbuild-linux-ppc64le "0.14.39" + esbuild-linux-riscv64 "0.14.39" + esbuild-linux-s390x "0.14.39" + esbuild-netbsd-64 "0.14.39" + esbuild-openbsd-64 "0.14.39" + esbuild-sunos-64 "0.14.39" + esbuild-windows-32 "0.14.39" + esbuild-windows-64 "0.14.39" + esbuild-windows-arm64 "0.14.39" escalade@^3.1.1: version "3.1.1" @@ -11952,10 +11945,10 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-source-polyfill@1.0.26: - version "1.0.26" - resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.26.tgz#86c04d088ef078279168eefa028f928fec5059a4" - integrity sha512-IwDLs9fUTcGAyacHBeS53T8wcEkDyDn0UP4tfQqJ4wQP8AyH0mszuQf2ULTylnpI0sMquzJ4usrNV7+uztwI9A== +event-source-polyfill@1.0.25: + version "1.0.25" + resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.25.tgz#d8bb7f99cb6f8119c2baf086d9f6ee0514b6d9c8" + integrity sha512-hQxu6sN1Eq4JjoI7ITdQeGGUN193A2ra83qC0Ltm9I2UJVAten3OFVN6k5RX4YWeCS0BoC8xg/5czOCIHVosQg== event-stream@=3.3.4: version "3.3.4" @@ -12204,11 +12197,11 @@ express-promise-router@^4.1.0: methods "^1.0.0" express-session@^1.17.1: - version "1.17.2" - resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz#397020374f9bf7997f891b85ea338767b30d0efd" - integrity sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ== + version "1.17.3" + resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz#14b997a15ed43e5949cb1d073725675dd2777f36" + integrity sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw== dependencies: - cookie "0.4.1" + cookie "0.4.2" cookie-signature "1.0.6" debug "2.6.9" depd "~2.0.0" @@ -13410,11 +13403,11 @@ grapheme-splitter@^1.0.4: integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== graphiql@^1.5.12, graphiql@^1.8.8: - version "1.8.8" - resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.8.8.tgz#eef760097b20901c0427f831ee6403fbdb2711b8" - integrity sha512-0AwnT7YnLU0Y+rQSZgdL7HxFJtAC2emyQAzsaqTglur/gSqw+4115LYi9tNRLGnFpxGE8giTslYLh9P0RdhiWg== + version "1.8.9" + resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.8.9.tgz#96063ace9379699e873da078bf0f2ae7062f370e" + integrity sha512-X+olqol3VfOrFrsAfYzgNbvHoEE0lDUtg52+f3yLeNY4Ens+rAH4RSdH4wVtoRdh3CafmhVsfLQvn04hHkgftQ== dependencies: - "@graphiql/toolkit" "^0.4.3" + "@graphiql/toolkit" "^0.4.4" codemirror "^5.65.3" codemirror-graphql "^1.3.0" copy-to-clipboard "^3.2.0" @@ -13503,9 +13496,9 @@ graphql@^15.5.1: integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== graphql@^16.0.0, graphql@^16.3.0: - version "16.4.0" - resolved "https://registry.npmjs.org/graphql/-/graphql-16.4.0.tgz#bb10b1b4683045dedcb67000eb4ad134a36c59e6" - integrity sha512-tYDNcRvKCcfHREZYje3v33NSrSD/ZpbWWdPtBtUUuXx9NCo/2QDxYzNqCnMvfsrnbwRpEHMovVrPu/ERoLrIRg== + version "16.5.0" + resolved "https://registry.npmjs.org/graphql/-/graphql-16.5.0.tgz#41b5c1182eaac7f3d47164fb247f61e4dfb69c85" + integrity sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA== grouped-queue@^2.0.0: version "2.0.0" @@ -14020,10 +14013,10 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -husky@^7.0.4: - version "7.0.4" - resolved "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" - integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== +husky@^8.0.0: + version "8.0.1" + resolved "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" + integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== hyphenate-style-name@^1.0.2, hyphenate-style-name@^1.0.3: version "1.0.3" @@ -14118,9 +14111,9 @@ immer@9.0.7: integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== immer@^9.0.1, immer@^9.0.7: - version "9.0.12" - resolved "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" - integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== + version "9.0.14" + resolved "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48" + integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw== immutable@^3.x.x: version "3.8.2" @@ -14357,7 +14350,7 @@ invert-kv@^1.0.0: resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= -ioredis@^5.0.3: +ioredis@^5.0.4: version "5.0.4" resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.0.4.tgz#0d4abfd818adfc5ef5029fddac4b8f503a1433b7" integrity sha512-qFJw3MnPNsJF1lcIOP3vztbsasOXK3nDdNAgjQj7t7/Bn/w10PGchTOpqylQNxjzPbLoYDu34LjeJtSWiKBntQ== @@ -15048,9 +15041,9 @@ isomorphic-form-data@^2.0.0: form-data "^2.3.2" isomorphic-git@^1.8.0: - version "1.17.1" - resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.17.1.tgz#ac5a095b78cf5ceef51954f5df4b1bdd24943e5f" - integrity sha512-JLZzAmc78yELH6+bZgMzqV0KGEi2duo+URWmyEnSbhhibHwDsMIlUw5tr1ZVHjC2CUQtU0X/5EY9Sbzsyx7nug== + version "1.17.2" + resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.17.2.tgz#d49eda3122dfa3b860f0c68d651297c6403b715f" + integrity sha512-KtYyJye7Ad1XSgObsw7dwn3OaEcGUy04BHv6D+qBz2BWY7T7q7HXBzoSOiVvVMbOo+K2EZ2MUT+g2QkpJCPQLQ== dependencies: async-lock "^1.1.0" clean-git-ref "^2.0.1" @@ -15803,7 +15796,7 @@ json-buffer@3.0.1, json-buffer@^3.0.1, json-buffer@~3.0.1: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -16185,11 +16178,11 @@ keyv@^3.0.0: json-buffer "3.0.0" keyv@^4.0.0, keyv@^4.0.3: - version "4.2.2" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.2.2.tgz#4b6f602c0228ef4d8214c03c520bef469ed6b768" - integrity sha512-uYS0vKTlBIjNCAUqrjlxmruxOEiZxZIHXyp32sdcGmP+ukFrmWUnE//RcPXJH3Vxrni1H2gsQbjHE0bH7MtMQQ== + version "4.2.7" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.2.7.tgz#00b8994d46098e8eb8c933cb29aaaf18be5effea" + integrity sha512-HeOstD8SXvtWoQhMMBCelcUuZsiV7T7MwsADtOXT0KuwYP9nCxrSoMDeLXNDTLN3VFSuRp38JzoGbbTboq3QQw== dependencies: - compress-brotli "^1.3.6" + compress-brotli "^1.3.8" json-buffer "3.0.1" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: @@ -18941,9 +18934,9 @@ openid-client@^4.1.1: oidc-token-hash "^5.0.1" openid-client@^5.1.3: - version "5.1.5" - resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.5.tgz#cac1e50015937e5af70be45e1ae5b1cb113f1f74" - integrity sha512-m41p7V/iXyqc0WZeo20uwKk8NPDAtYd3JS0uWjttcqwvFo4YNYAKegMAMea1qG5RClddQ6rV9ec/TP6ZvsCrYw== + version "5.1.6" + resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.6.tgz#e5eb2032ecfdcfc108660b5c525910a14e352f11" + integrity sha512-HTFaXWdUHvLFw4GaEMgC0jXYBgpjgzQQNHW1pZsSqJorSgrXzxJ+4u/LWCGaClDEse5HLjXRV+zU5Bn3OefiZw== dependencies: jose "^4.1.4" lru-cache "^6.0.0" @@ -20606,14 +20599,14 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" -puppeteer@^13.1.1: - version "13.7.0" - resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-13.7.0.tgz#18e16f83e397cf02f7a0804c67c1603d381cfb0b" - integrity sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA== +puppeteer@^14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-14.0.0.tgz#829e97b70fa81746bb88ec2d72f11a7429cc84ab" + integrity sha512-Aj/cySGBMWpUYEWV0YOcwyhq5lOxuuiGScgdj/OvslAm/ydoywiI8OzAIXT4HzKmNTmzm/fKKHHtcsQa/fFgdw== dependencies: cross-fetch "3.1.5" debug "4.3.4" - devtools-protocol "0.0.981744" + devtools-protocol "0.0.982423" extract-zip "2.0.1" https-proxy-agent "5.0.1" pkg-dir "4.2.0" @@ -20622,7 +20615,7 @@ puppeteer@^13.1.1: rimraf "3.0.2" tar-fs "2.1.1" unbzip2-stream "1.4.3" - ws "8.5.0" + ws "8.6.0" q@^1.5.1: version "1.5.1" @@ -20775,6 +20768,15 @@ rc-progress@3.2.4: classnames "^2.2.6" rc-util "^5.16.1" +rc-progress@3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.2.tgz#57362d49bb6b7b09fec84bf18220619294bde675" + integrity sha512-m+1LtVlXIomz8lcghfF/kViT5h/NtdWp87hnFL+FlnrxyZCEuB4N5BKNN6ctZa3a1Mae+4SMO8AG5lScjU06Ig== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.16.1" + rc-util@^5.16.1: version "5.16.1" resolved "https://registry.npmjs.org/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" @@ -20900,9 +20902,9 @@ react-helmet@6.1.0: react-side-effect "^2.1.0" react-hook-form@^7.12.2, react-hook-form@^7.13.0: - version "7.30.0" - resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz#c9e2fd54d3627e43bd94bf38ef549df2e80c1371" - integrity sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ== + version "7.31.1" + resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.31.1.tgz#16c357dd366bc226172e6acbb5a1672873bbfb28" + integrity sha512-QjtjZ8r8KtEBWWpcXLyQordCraTFxILtyQpaz5KLLxN2YzcC+FZ9LLtOnNGuOnzZo9gCoB+viK3ZHV9Mb2htmQ== react-hot-loader@^4.13.0: version "4.13.0" @@ -25137,9 +25139,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5, webpack@^5.66.0: - version "5.72.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz#f8bc40d9c6bb489a4b7a8a685101d6022b8b6e28" - integrity sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w== + version "5.72.1" + resolved "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz#3500fc834b4e9ba573b9f430b2c0a61e1bb57d13" + integrity sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -25150,13 +25152,13 @@ webpack@^5, webpack@^5.66.0: acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.9.2" + enhanced-resolve "^5.9.3" es-module-lexer "^0.9.0" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" graceful-fs "^4.2.9" - json-parse-better-errors "^1.0.2" + json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" @@ -25435,20 +25437,20 @@ write-pkg@^4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@8.5.0, ws@^8.4.2: - version "8.5.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" - integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== +ws@8.6.0, ws@^8.0.0, ws@^8.3.0: + version "8.6.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23" + integrity sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw== ws@^7.3.1, ws@^7.4.6: version "7.5.7" resolved "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -ws@^8.0.0, ws@^8.3.0: - version "8.6.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23" - integrity sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw== +ws@^8.4.2: + version "8.5.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== ws@~7.4.2: version "7.4.6" @@ -25855,9 +25857,9 @@ zip-stream@^4.1.0: readable-stream "^3.6.0" zod@^3.11.6, zod@^3.9.5: - version "3.15.1" - resolved "https://registry.npmjs.org/zod/-/zod-3.15.1.tgz#9e404cd8002ccffb03baa94cff2e1638ed49d82f" - integrity sha512-WAdjcoOxa4S9oc/u7fTbC3CC7uVqptLLU0LKqS8RDBOrCXp2t5avM8BUfgNVZJymGWAx6SEUYxWPPoYuQ5rgwQ== + version "3.16.0" + resolved "https://registry.npmjs.org/zod/-/zod-3.16.0.tgz#edfdbf77fcc9a5af13a2630a44bdda5b90e759b7" + integrity sha512-szrIkryADbTM+xBt2a1KoS2CJQXec4f9xG78bj5MJeEH/XqmmHpnO+fG3IE115AKBJak+2HrbxLZkc9mhdbDKA== zustand@3.6.9: version "3.6.9"