diff --git a/.changeset/rotten-rings-confess.md b/.changeset/rotten-rings-confess.md new file mode 100644 index 0000000000..8948a90347 --- /dev/null +++ b/.changeset/rotten-rings-confess.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-newrelic-dashboard': minor +--- + +Changes in `newrelic-dashboard` plugin: + +- Make DashboardSnapshotList component public +- Settle discrepancies in the exported API +- Deprecate DashboardSnapshotComponent diff --git a/.changeset/smooth-rings-mate.md b/.changeset/smooth-rings-mate.md new file mode 100644 index 0000000000..f46ef2cb5c --- /dev/null +++ b/.changeset/smooth-rings-mate.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +Added support for string `fontSize` values (e.g. `"2.5rem"`) in themes in addition to numbers. Also added an optional `fontFamily` prop for header typography variants to allow further customization. diff --git a/.changeset/twenty-bags-sin.md b/.changeset/twenty-bags-sin.md new file mode 100644 index 0000000000..797fd5bfef --- /dev/null +++ b/.changeset/twenty-bags-sin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights': patch +--- + +Export `ScorecardInfo` and `ScorecardsList` components to be able to use manually queried check results directly. diff --git a/.changeset/unlucky-experts-breathe.md b/.changeset/unlucky-experts-breathe.md new file mode 100644 index 0000000000..018b1826d2 --- /dev/null +++ b/.changeset/unlucky-experts-breathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Added support for the existing routing system. diff --git a/.changeset/wild-queens-grab.md b/.changeset/wild-queens-grab.md new file mode 100644 index 0000000000..287dc0482e --- /dev/null +++ b/.changeset/wild-queens-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-playlist': patch +--- + +Updated Playlist read me with additional screenshots diff --git a/docs/plugins/testing.md b/docs/plugins/testing.md index 2fa086c444..3a7da2d410 100644 --- a/docs/plugins/testing.md +++ b/docs/plugins/testing.md @@ -18,11 +18,11 @@ Running all tests: yarn test -Running an individual test (e.g. `MyComponent.test.js`): +Running an individual test (e.g. `MyComponent.test.tsx`): yarn test MyComponent -To run both `MyComponent.test.js` and `MyControl.test.js` suite of tests: +To run both `MyComponent.test.tsx` and `MyControl.test.tsx` suite of tests: yarn test MyCo @@ -32,9 +32,9 @@ working on. ## Naming Test Files -Tests should be named `[filename].test.js`. +Tests should be named `[filename].test.ts`, or `[filename].test.tsx` if it contains JSX (as is the case for a lot of React tests, e.g. components). -For example, the tests for **`Link.js`** exist in the file **`Link.test.js`**. +For example, the tests for **`Link.tsx`** exist in the file **`Link.test.tsx`**. ## Third-Party Dependencies @@ -183,9 +183,9 @@ data then it actually does it. this way both tests fail if the data loading part breaks and the next developer immediately know the problem is that the data loading is broken, not that the loading indicator is broken. -# Examples +## Examples -## Utility Functions +### Utility Functions A utility function is a function with no side effects. It takes in arguments and returns a result or displays an error or console message, like so: @@ -241,12 +241,12 @@ it('Works with midCharIx', () => { }); ``` -## Non-React Classes +### Non-React Classes Testing a JavaScript object which is _not_ a React component follows a lot of the same principles as testing objects in other languages. -### API Testing Principles +#### API Testing Principles Testing an API involves verifying four things: @@ -255,7 +255,7 @@ Testing an API involves verifying four things: 3. Server response is translated into an expected JavaScript object. 4. Server errors are handled gracefully. -### Mocking API Calls +#### Mocking API Calls [Mocking in Jest](https://facebook.github.io/jest/docs/en/mock-functions.html) involves wrapping existing functions (like an API call function) with an @@ -263,52 +263,46 @@ alternative. For example: -**`./MyApi.js`** +**`./MyApi.ts`** ```ts -export { - fetchSomethingFromServer: () => { - // Live production call to a URI. Must be avoided during testing! - return fetch('blah'); - } -}; -``` - -**`./__mocks__/MyApi.js`** - -```ts -export { - fetchSomethingFromServer: () => { - // Simulate a production call, but avoid jest and just use a promise - return Promise.resolve('some result object simulating server data here'); - } +export async function fetchSomethingFromServer() { + // Live production call to a URI. Must be avoided during testing! + return fetch('blah'); } ``` -**`./MyApi.test.js`** +**`./__mocks__/MyApi.ts`** ```ts -/* eslint-disable import/first */ +export async function fetchSomethingFromServer() { + // Simulate a production call response + return 'some result object simulating server data here'; +} +``` -jest.mock('./MyApi'); // Instruct Jest to swap all future imports of './MyApi.js' to './__mocks__/MyApi.js' +**`./MyApi.test.ts`** -import MyApi from './MyApi'; // Will actually return the contents of the file in the __mocks__ folder now +```ts +// This import will actually return the contents of the file in the +// __mocks__ folder now, due to the jest.mock line below +import { fetchSomethingFromServer } from './MyApi'; -it('loads data', done => { - MyApi.fetchSomethingFromServer().then(result => { - expect(result).toBe('some result object simulating server data here'); - done(); - }); +// This instructs Jest to swap all imports of './MyApi.ts' to +// './__mocks__/MyApi.ts' - this gets automatically hoisted to the top +// of the file +jest.mock('./MyApi'); + +it('loads data', async () => { + await expect(fetchSomethingFromServer()).resolves.toBe( + 'some result object simulating server data here', + ); }); ``` -Note: make sure you disable the eslint `'import/first'` rule at the top of the -file since technically you are not allowed by the default settings to have an -import after the `jest.mock` call. +### React Components -## React Components - -### Working with the React Lifecycle +#### Working with the React Lifecycle The [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html) is asynchronous. @@ -317,7 +311,7 @@ When you call `setState` or update the `props` of a component, there are several asynchronous stages that must occur before a rerender. Note the following example: -```jsx +```tsx class MyComponent extends Component { load() { this.setState({loading: true}); @@ -350,7 +344,7 @@ For more information: - [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html) -### Accessing `store`, `theme`, routing, browser history, etc. +#### Accessing `store`, `theme`, routing, browser history, etc The Backstage application has several core providers at its root. To run your test wrapped in a "sample" Backstage application, you can use our utility @@ -369,6 +363,6 @@ functions: Note: wrapping in the test application **requires** you to do a `find()` or `dive()` since the wrapped component is now the application. -# Debugging Jest Tests +## Debugging Jest Tests You can find it [here](https://backstage.io/docs/local-dev/cli-build-system#debugging-jest-tests) diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 27b077b8da..81d3ccfb42 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2604,90 +2604,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-arm64@npm:1.3.90" +"@swc/core-darwin-arm64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-arm64@npm:1.3.92" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-x64@npm:1.3.90" +"@swc/core-darwin-x64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-x64@npm:1.3.92" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" +"@swc/core-linux-arm-gnueabihf@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.92" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" +"@swc/core-linux-arm64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" +"@swc/core-linux-arm64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" +"@swc/core-linux-x64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-musl@npm:1.3.90" +"@swc/core-linux-x64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-musl@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" +"@swc/core-win32-arm64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.92" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" +"@swc/core-win32-ia32-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.92" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" +"@swc/core-win32-x64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.92" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.90 - resolution: "@swc/core@npm:1.3.90" + version: 1.3.92 + resolution: "@swc/core@npm:1.3.92" dependencies: - "@swc/core-darwin-arm64": 1.3.90 - "@swc/core-darwin-x64": 1.3.90 - "@swc/core-linux-arm-gnueabihf": 1.3.90 - "@swc/core-linux-arm64-gnu": 1.3.90 - "@swc/core-linux-arm64-musl": 1.3.90 - "@swc/core-linux-x64-gnu": 1.3.90 - "@swc/core-linux-x64-musl": 1.3.90 - "@swc/core-win32-arm64-msvc": 1.3.90 - "@swc/core-win32-ia32-msvc": 1.3.90 - "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/core-darwin-arm64": 1.3.92 + "@swc/core-darwin-x64": 1.3.92 + "@swc/core-linux-arm-gnueabihf": 1.3.92 + "@swc/core-linux-arm64-gnu": 1.3.92 + "@swc/core-linux-arm64-musl": 1.3.92 + "@swc/core-linux-x64-gnu": 1.3.92 + "@swc/core-linux-x64-musl": 1.3.92 + "@swc/core-win32-arm64-msvc": 1.3.92 + "@swc/core-win32-ia32-msvc": 1.3.92 + "@swc/core-win32-x64-msvc": 1.3.92 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -2716,7 +2716,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab + checksum: 88c0c62ff790e896180862c341be8bae98baf0a5c5e87f2f04f49e14b8c4fba460d6b352618b4dda066c8ae6bf152cd843eab25837f38128175208b8c0635721 languageName: node linkType: hard @@ -9421,13 +9421,13 @@ __metadata: linkType: hard "postcss@npm:^8.4.17, postcss@npm:^8.4.19, postcss@npm:^8.4.21": - version: 8.4.23 - resolution: "postcss@npm:8.4.23" + version: 8.4.31 + resolution: "postcss@npm:8.4.31" dependencies: nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 8bb9d1b2ea6e694f8987d4f18c94617971b2b8d141602725fedcc2222fdc413b776a6e1b969a25d627d7b2681ca5aabb56f59e727ef94072e1b6ac8412105a2f + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 5fb84070d4..477cf8f736 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -42,6 +42,7 @@ "@backstage/plugin-graphiql": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", + "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.11.3", "@types/react": "^16.13.1 || ^17.0.0", diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts new file mode 100644 index 0000000000..c64dc7a3b9 --- /dev/null +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts @@ -0,0 +1,528 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + BackstagePlugin, + RouteRef, + createRouteRef, +} from '@backstage/core-plugin-api'; +import { extractRouteInfoFromInstanceTree } from './extractRouteInfoFromInstanceTree'; +import { + Extension, + coreExtensionData, + createExtension, + createExtensionInput, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { createInstances } from '../wiring/createApp'; +import { MockConfigApi } from '@backstage/test-utils'; + +const ref1 = createRouteRef({ id: 'page1' }); +const ref2 = createRouteRef({ id: 'page2' }); +const ref3 = createRouteRef({ id: 'page3' }); +const ref4 = createRouteRef({ id: 'page4' }); +const ref5 = createRouteRef({ id: 'page5' }); +const refOrder = [ref1, ref2, ref3, ref4, ref5]; + +function createTestExtension(options: { + id: string; + at?: string; + path?: string; + routeRef?: RouteRef; +}) { + return createExtension({ + id: options.id, + at: options.at ?? 'core.routes/children', + output: { + element: coreExtensionData.reactElement, + path: coreExtensionData.routePath.optional(), + routeRef: coreExtensionData.routeRef.optional(), + }, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + factory({ bind }) { + bind({ + path: options.path, + routeRef: options.routeRef, + element: React.createElement('div'), + }); + }, + }); +} + +function routeInfoFromExtensions(extensions: Extension[]) { + const plugin = createPlugin({ + id: 'test', + extensions, + }); + const { rootInstances } = createInstances({ + config: new MockConfigApi({}), + plugins: [plugin], + }); + + return extractRouteInfoFromInstanceTree(rootInstances); +} + +function sortedEntries(map: Map): [RouteRef, T][] { + return Array.from(map).sort( + ([a], [b]) => refOrder.indexOf(a) - refOrder.indexOf(b), + ); +} + +function routeObj( + path: string, + refs: RouteRef[], + children: any[] = [], + type: 'mounted' | 'gathered' = 'mounted', + backstagePlugin?: BackstagePlugin, +) { + return { + path: path, + caseSensitive: false, + element: type, + routeRefs: new Set(refs), + children: [ + { + path: '*', + caseSensitive: false, + element: 'match-all', + routeRefs: new Set(), + plugins: new Set(), + }, + ...children, + ], + plugins: backstagePlugin ? new Set([backstagePlugin]) : new Set(), + }; +} + +describe('discovery', () => { + it('should collect routes', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'nothing', + path: 'nothing', + }), + createTestExtension({ + id: 'page1', + path: 'foo', + routeRef: ref1, + }), + createTestExtension({ + id: 'page2', + at: 'page1/children', + path: 'bar/:id', + routeRef: ref2, + }), + createTestExtension({ + id: 'page3', + at: 'page2/children', + path: 'baz', + routeRef: ref3, + }), + createTestExtension({ + id: 'page4', + path: 'divsoup', + routeRef: ref4, + }), + createTestExtension({ + id: 'page5', + at: 'page1/children', + path: 'blop', + routeRef: ref5, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'foo'], + [ref2, 'bar/:id'], + [ref3, 'baz'], + [ref4, 'divsoup'], + [ref5, 'blop'], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, ref1], + [ref3, ref2], + [ref4, undefined], + [ref5, ref1], + ]); + expect(info.routeObjects).toEqual([ + routeObj('nothing', []), + routeObj( + 'foo', + [ref1], + [ + routeObj( + 'bar/:id', + [ref2], + [routeObj('baz', [ref3], undefined, undefined, expect.any(Object))], + undefined, + expect.any(Object), + ), + routeObj('blop', [ref5], undefined, undefined, expect.any(Object)), + ], + undefined, + expect.any(Object), + ), + routeObj('divsoup', [ref4], undefined, undefined, expect.any(Object)), + ]); + }); + + it('should handle all react router Route patterns', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'page1', + path: 'foo', + routeRef: ref1, + }), + createTestExtension({ + id: 'page2', + at: 'page1/children', + path: 'bar/:id', + routeRef: ref2, + }), + createTestExtension({ + id: 'page3', + path: 'baz', + routeRef: ref3, + }), + createTestExtension({ + id: 'page4', + at: 'page3/children', + path: 'divsoup', + routeRef: ref4, + }), + createTestExtension({ + id: 'page5', + at: 'page3/children', + path: 'blop', + routeRef: ref5, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'foo'], + [ref2, 'bar/:id'], + [ref3, 'baz'], + [ref4, 'divsoup'], + [ref5, 'blop'], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, ref1], + [ref3, undefined], + [ref4, ref3], + [ref5, ref3], + ]); + }); + + it('should strip leading slashes in route paths', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'page1', + path: '/foo', + routeRef: ref1, + }), + createTestExtension({ + id: 'page2', + at: 'page1/children', + path: '/bar/:id', + routeRef: ref2, + }), + createTestExtension({ + id: 'page3', + path: '/baz', + routeRef: ref3, + }), + createTestExtension({ + id: 'page4', + at: 'page3/children', + path: '/divsoup', + routeRef: ref4, + }), + createTestExtension({ + id: 'page5', + at: 'page3/children', + path: '/blop', + routeRef: ref5, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'foo'], + [ref2, 'bar/:id'], + [ref3, 'baz'], + [ref4, 'divsoup'], + [ref5, 'blop'], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, ref1], + [ref3, undefined], + [ref4, ref3], + [ref5, ref3], + ]); + }); + + it('should use the route aggregator key to bind child routes to the same path', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'foo', + path: 'foo', + }), + createTestExtension({ + id: 'page1', + at: 'foo/children', + routeRef: ref1, + }), + createTestExtension({ + id: 'fooChild', + at: 'foo/children', + }), + createTestExtension({ + id: 'page2', + at: 'fooChild/children', + routeRef: ref2, + }), + createTestExtension({ + id: 'fooEmpty', + }), + createTestExtension({ + id: 'page3', + path: 'bar', + routeRef: ref3, + }), + createTestExtension({ + id: 'page3Child', + at: 'page3/children', + path: '', + }), + createTestExtension({ + id: 'page4', + at: 'page3Child/children', + routeRef: ref4, + }), + createTestExtension({ + id: 'page5', + at: 'page4/children', + routeRef: ref5, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'foo'], + [ref2, 'foo'], + [ref3, 'bar'], + [ref4, ''], + [ref5, ''], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, undefined], + [ref3, undefined], + [ref4, ref3], + [ref5, ref3], + ]); + expect(info.routeObjects).toEqual([ + routeObj('foo', [ref1, ref2], [], 'mounted', expect.any(Object)), + routeObj( + 'bar', + [ref3], + [routeObj('', [ref4, ref5], [], 'mounted', expect.any(Object))], + 'mounted', + expect.any(Object), + ), + ]); + }); + + it('should use the route aggregator but stop when encountering explicit path', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'page1', + path: 'foo', + routeRef: ref1, + }), + createTestExtension({ + id: 'page1Child', + at: 'page1/children', + path: 'bar', + }), + createTestExtension({ + id: 'page2', + at: 'page1Child/children', + routeRef: ref2, + }), + createTestExtension({ + id: 'page3', + at: 'page2/children', + path: 'baz', + routeRef: ref3, + }), + createTestExtension({ + id: 'page4', + at: 'page3/children', + path: '/blop', + routeRef: ref4, + }), + createTestExtension({ + id: 'page5', + at: 'page2/children', + routeRef: ref5, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'foo'], + [ref2, 'bar'], + [ref3, 'baz'], + [ref4, 'blop'], + [ref5, 'bar'], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, ref1], + [ref3, ref2], + [ref4, ref3], + [ref5, ref1], + ]); + expect(info.routeObjects).toEqual([ + routeObj( + 'foo', + [ref1], + [ + routeObj( + 'bar', + [ref2, ref5], + [ + routeObj( + 'baz', + [ref3], + [ + routeObj( + 'blop', + [ref4], + undefined, + undefined, + expect.any(Object), + ), + ], + undefined, + expect.any(Object), + ), + ], + 'mounted', + expect.any(Object), + ), + ], + undefined, + expect.any(Object), + ), + ]); + }); + + it('should account for loose route paths', () => { + const info = routeInfoFromExtensions([ + createTestExtension({ + id: 'r', + path: 'r', + }), + createTestExtension({ + id: 'page1', + at: 'r/children', + path: 'x', + routeRef: ref1, + }), + createTestExtension({ + id: 'y', + path: 'y', + at: 'r/children', + }), + createTestExtension({ + id: 'page2', + at: 'y/children', + path: '1', + routeRef: ref2, + }), + createTestExtension({ + id: 'page3', + at: 'page2/children', + path: 'a', + routeRef: ref3, + }), + createTestExtension({ + id: 'page4', + at: 'page2/children', + path: 'b', + routeRef: ref4, + }), + ]); + + expect(sortedEntries(info.routePaths)).toEqual([ + [ref1, 'r/x'], + [ref2, 'r/y/1'], + [ref3, 'a'], + [ref4, 'b'], + ]); + expect(sortedEntries(info.routeParents)).toEqual([ + [ref1, undefined], + [ref2, undefined], + [ref3, ref2], + [ref4, ref2], + ]); + expect(info.routeObjects).toEqual([ + routeObj( + 'r', + [], + [ + routeObj('x', [ref1], [], 'mounted', expect.any(Object)), + routeObj( + 'y', + [], + [ + routeObj( + '1', + [ref2], + [ + routeObj( + 'a', + [ref3], + undefined, + 'mounted', + expect.any(Object), + ), + routeObj( + 'b', + [ref4], + undefined, + 'mounted', + expect.any(Object), + ), + ], + 'mounted', + expect.any(Object), + ), + ], + 'mounted', + ), + ], + ), + ]); + }); +}); diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts new file mode 100644 index 0000000000..30305b0d2c --- /dev/null +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts @@ -0,0 +1,159 @@ +/* + * Copyright 2023 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 { RouteRef } from '@backstage/core-plugin-api'; +import { coreExtensionData } from '@backstage/frontend-plugin-api'; +import { ExtensionInstance } from '../wiring/createExtensionInstance'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { BackstageRouteObject } from '../../../core-app-api/src/routing/types'; +import { toLegacyPlugin } from '../wiring/createApp'; + +// We always add a child that matches all subroutes but without any route refs. This makes +// sure that we're always able to match each route no matter how deep the navigation goes. +// The route resolver then takes care of selecting the most specific match in order to find +// mount points that are as deep in the routing tree as possible. +export const MATCH_ALL_ROUTE: BackstageRouteObject = { + caseSensitive: false, + path: '*', + element: 'match-all', // These elements aren't used, so we add in a bit of debug information + routeRefs: new Set(), + plugins: new Set(), +}; + +// Joins a list of paths together, avoiding trailing and duplicate slashes +export function joinPaths(...paths: string[]): string { + const normalized = paths.join('/').replace(/\/\/+/g, '/'); + if (normalized !== '/' && normalized.endsWith('/')) { + return normalized.slice(0, -1); + } + return normalized; +} + +export function extractRouteInfoFromInstanceTree(roots: ExtensionInstance[]): { + routePaths: Map; + routeParents: Map; + routeObjects: BackstageRouteObject[]; +} { + // This tracks the route path for each route ref, the value is the route path relative to the parent ref + const routePaths = new Map(); + // This tracks the parents of each route ref. To find the full path of any route ref you traverse + // upwards in this tree and substitute each route ref for its route path along then way. + const routeParents = new Map(); + // This route object tree is passed to react-router in order to be able to look up the current route + // ref or extension/source based on our current location. + const routeObjects = new Array(); + + function visit( + current: ExtensionInstance, + collectedPath?: string, + foundRefForCollectedPath: boolean = false, + parentRef?: RouteRef, + candidateParentRef?: RouteRef, + parentObj?: BackstageRouteObject, + ) { + const routePath = current + .getData(coreExtensionData.routePath) + ?.replace(/^\//, ''); + const routeRef = current.getData(coreExtensionData.routeRef); + const parentChildren = parentObj?.children ?? routeObjects; + let currentObj = parentObj; + + let newCollectedPath = collectedPath; + let newFoundRefForCollectedPath = foundRefForCollectedPath; + + let newParentRef = parentRef; + let newCandidateParentRef = candidateParentRef; + + // Whenever a route path is encountered, a new node is created in the routing tree. + if (routePath !== undefined) { + currentObj = { + path: routePath, + element: 'mounted', + routeRefs: new Set(), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + plugins: new Set(), + }; + parentChildren.push(currentObj); + + // Each route path that we discover creates a new node in the routing tree, at that point + // we also switch out our candidate parent ref to be the active one. + newParentRef = candidateParentRef; + newCandidateParentRef = undefined; + + // We need to collect and concatenate route paths until the path has been assigned a route ref: + // Once we find a route ref the collection starts over from an empty path, that way each route + // path assignment only contains the diff from the parent ref. + if (newFoundRefForCollectedPath) { + newCollectedPath = routePath; + newFoundRefForCollectedPath = false; + } else { + newCollectedPath = collectedPath + ? joinPaths(collectedPath, routePath) + : routePath; + } + } + + // Whenever a route ref is encountered, we need to give it a route path and position in the ref tree. + if (routeRef) { + const routeRefId = (routeRef as any).id; // TODO: properly + if (routeRefId !== current.id) { + throw new Error( + `Route ref '${routeRefId}' must have the same ID as extension '${current.id}'`, + ); + } + + // The first route ref we find after encountering a route path is selected to be used as the + // parent ref further down the tree. We don't start using this candidate ref until we encounter + // another route path though, at which point we repeat the process and select another candidate. + if (!newCandidateParentRef) { + newCandidateParentRef = routeRef; + } + + // Check if we've encountered any route paths since the closest route ref, in that case we assign + // that path to this and following route refs until we encounter another route path. + if (newCollectedPath !== undefined) { + routePaths.set(routeRef, newCollectedPath); + newFoundRefForCollectedPath = true; + } + + routeParents.set(routeRef, newParentRef); + currentObj?.routeRefs.add(routeRef); + if (current.source) { + currentObj?.plugins.add(toLegacyPlugin(current.source)); + } + } + + for (const children of current.attachments.values()) { + for (const child of children) { + visit( + child, + newCollectedPath, + newFoundRefForCollectedPath, + newParentRef, + newCandidateParentRef, + currentObj, + ); + } + } + } + + for (const root of roots) { + visit(root); + } + + return { routePaths, routeParents, routeObjects }; +} diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index deb19d919d..540b47849f 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -74,6 +74,8 @@ import { defaultConfigLoaderSync } from '../../../core-app-api/src/app/defaultCo // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { overrideBaseUrlConfigs } from '../../../core-app-api/src/app/overrideBaseUrlConfigs'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { RoutingProvider as LegacyRoutingProvider } from '../../../core-app-api/src/routing/RoutingProvider'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { apis as defaultApis, components as defaultComponents, @@ -82,6 +84,8 @@ import { import { BrowserRouter, Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; import { DarkTheme, LightTheme } from '../extensions/themes'; +import { extractRouteInfoFromInstanceTree } from '../routing/extractRouteInfoFromInstanceTree'; +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; /** @public */ export interface ExtensionTreeNode { @@ -281,7 +285,7 @@ export function createApp(options: { config, }); - const routePaths = extractRouteInfoFromInstanceTree(rootInstances); + const routeInfo = extractRouteInfoFromInstanceTree(rootInstances); const coreInstance = rootInstances.find(({ id }) => id === 'core'); if (!coreInstance) { @@ -304,10 +308,15 @@ export function createApp(options: { - - {/* TODO: set base path using the logic from AppRouter */} - {rootElements} - + + + {/* TODO: set base path using the logic from AppRouter */} + {rootElements} + + @@ -328,25 +337,40 @@ export function createApp(options: { }; } -function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { +// Make sure that we only convert each new plugin instance to its legacy equivalent once +const legacyPluginStore = getOrCreateGlobalSingleton( + 'legacy-plugin-compatibility-store', + () => new WeakMap(), +); + +export function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { + let legacy = legacyPluginStore.get(plugin); + if (legacy) { + return legacy; + } + const errorMsg = 'Not implemented in legacy plugin compatibility layer'; const notImplemented = () => { throw new Error(errorMsg); }; - return { + + legacy = { getId(): string { return plugin.id; }, - get routes(): never { - throw new Error(errorMsg); + get routes() { + return {}; }, - get externalRoutes(): never { - throw new Error(errorMsg); + get externalRoutes() { + return {}; }, getApis: notImplemented, getFeatureFlags: notImplemented, provide: notImplemented, }; + + legacyPluginStore.set(plugin, legacy); + return legacy; } function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { @@ -458,38 +482,3 @@ function createApiHolder( return new ApiResolver(factoryRegistry); } - -/** @internal */ -export function extractRouteInfoFromInstanceTree( - roots: ExtensionInstance[], -): Map { - const results = new Map(); - - function visit(current: ExtensionInstance, basePath: string) { - const routePath = current.getData(coreExtensionData.routePath) ?? ''; - const routeRef = current.getData(coreExtensionData.routeRef); - - // TODO: join paths in a more robust way - const fullPath = basePath + routePath; - if (routeRef) { - const routeRefId = (routeRef as any).id; // TODO: properly - if (routeRefId !== current.id) { - throw new Error( - `Route ref '${routeRefId}' must have the same ID as extension '${current.id}'`, - ); - } - results.set(routeRef, fullPath); - } - - for (const children of current.attachments.values()) { - for (const child of children) { - visit(child, fullPath); - } - } - } - - for (const root of roots) { - visit(root, ''); - } - return results; -} diff --git a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts index afa3cbfefc..18551eb8da 100644 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts +++ b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts @@ -36,6 +36,8 @@ export interface ExtensionInstance { * Maps input names to the actual instances given to them. */ readonly attachments: Map; + + readonly source?: BackstagePlugin; } function resolveInputData( @@ -141,7 +143,7 @@ export function createExtensionInstance(options: { getData(ref: ExtensionDataRef): T | undefined { return extensionData.get(ref.id) as T | undefined; }, - + source, attachments, }; } diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index d6380ee6e8..4ab05e8770 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -117,32 +117,38 @@ export type BackstageTypography = { htmlFontSize: number; fontFamily: string; h1: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h2: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h3: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h4: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h5: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h6: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; diff --git a/packages/theme/src/base/createBaseThemeOptions.ts b/packages/theme/src/base/createBaseThemeOptions.ts index bca56114d7..f0c8ab5fe9 100644 --- a/packages/theme/src/base/createBaseThemeOptions.ts +++ b/packages/theme/src/base/createBaseThemeOptions.ts @@ -57,7 +57,7 @@ export function createBaseThemeOptions( throw new Error(`${defaultPageTheme} is not defined in pageTheme.`); } - const defaultTypography = { + const defaultTypography: BackstageTypography = { htmlFontSize, fontFamily, h1: { diff --git a/packages/theme/src/base/types.ts b/packages/theme/src/base/types.ts index 3e34a0abb7..d62d944741 100644 --- a/packages/theme/src/base/types.ts +++ b/packages/theme/src/base/types.ts @@ -124,32 +124,38 @@ export type BackstageTypography = { htmlFontSize: number; fontFamily: string; h1: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h2: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h3: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h4: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h5: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; h6: { - fontSize: number; + fontFamily?: string; + fontSize: number | string; fontWeight: number; marginBottom: number; }; diff --git a/plugins/git-release-manager/src/plugin.test.ts b/plugins/git-release-manager/src/plugin.test.ts index b293ea05eb..055482dd7b 100644 --- a/plugins/git-release-manager/src/plugin.test.ts +++ b/plugins/git-release-manager/src/plugin.test.ts @@ -18,15 +18,15 @@ import * as plugin from './plugin'; describe('git-release-manager', () => { it('should export plugin & friends', () => { - expect(Object.keys(plugin)).toMatchInlineSnapshot(` + expect(Object.keys(plugin).sort()).toMatchInlineSnapshot(` [ - "gitReleaseManagerApiRef", - "constants", - "helpers", - "components", - "testHelpers", - "gitReleaseManagerPlugin", "GitReleaseManagerPage", + "components", + "constants", + "gitReleaseManagerApiRef", + "gitReleaseManagerPlugin", + "helpers", + "testHelpers", ] `); }); diff --git a/plugins/newrelic-dashboard/api-report.md b/plugins/newrelic-dashboard/api-report.md index ce7b8d5b7e..283523d781 100644 --- a/plugins/newrelic-dashboard/api-report.md +++ b/plugins/newrelic-dashboard/api-report.md @@ -11,12 +11,22 @@ import { JSX as JSX_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; // @public +export const DashboardSnapshot: (props: { + guid: string; + name: string; + permalink: string; +}) => JSX_2.Element; + +// @public @deprecated export const DashboardSnapshotComponent: (props: { guid: string; name: string; permalink: string; }) => JSX_2.Element; +// @public +export const DashboardSnapshotList: (props: { guid: string }) => JSX_2.Element; + // @public (undocumented) export const EntityNewRelicDashboardCard: () => JSX_2.Element; diff --git a/plugins/newrelic-dashboard/src/index.ts b/plugins/newrelic-dashboard/src/index.ts index ba87b8a514..bbdfb70190 100644 --- a/plugins/newrelic-dashboard/src/index.ts +++ b/plugins/newrelic-dashboard/src/index.ts @@ -18,6 +18,8 @@ export { newRelicDashboardPlugin, EntityNewRelicDashboardCard, EntityNewRelicDashboardContent, + DashboardSnapshot, + DashboardSnapshotList, DashboardSnapshotComponent, } from './plugin'; export { isNewRelicDashboardAvailable } from './Router'; diff --git a/plugins/newrelic-dashboard/src/plugin.ts b/plugins/newrelic-dashboard/src/plugin.ts index 51be731ca7..360f1cb911 100644 --- a/plugins/newrelic-dashboard/src/plugin.ts +++ b/plugins/newrelic-dashboard/src/plugin.ts @@ -52,7 +52,7 @@ export const newRelicDashboardPlugin = createPlugin({ /** @public */ export const EntityNewRelicDashboardContent = newRelicDashboardPlugin.provide( createComponentExtension({ - name: 'EntityNewRelicDashboardPage', + name: 'EntityNewRelicDashboardContent', component: { lazy: () => import('./Router').then(m => m.Router), }, @@ -62,7 +62,7 @@ export const EntityNewRelicDashboardContent = newRelicDashboardPlugin.provide( /** @public */ export const EntityNewRelicDashboardCard = newRelicDashboardPlugin.provide( createComponentExtension({ - name: 'EntityNewRelicDashboardListComponent', + name: 'EntityNewRelicDashboardCard', component: { lazy: () => import('./components/NewRelicDashboard/DashboardEntityList').then( @@ -80,9 +80,9 @@ export const EntityNewRelicDashboardCard = newRelicDashboardPlugin.provide( * * @public */ -export const DashboardSnapshotComponent = newRelicDashboardPlugin.provide( +export const DashboardSnapshot = newRelicDashboardPlugin.provide( createComponentExtension({ - name: 'DashboardSnapshotComponent', + name: 'DashboardSnapshot', component: { lazy: () => import( @@ -91,3 +91,33 @@ export const DashboardSnapshotComponent = newRelicDashboardPlugin.provide( }, }), ); + +/** + * Render dashboard snapshots from Newrelic in backstage. Use dashboards which have the tag `isDashboardPage: true` + * + * @deprecated + * Use DashboardSnapshot export name instead + * + * @public + */ +export const DashboardSnapshotComponent = DashboardSnapshot; + +/** + * Render a dashboard snapshots list from Newrelic in backstage. Use dashboards which have the tag `isDashboardPage: true` + * + * @remarks + * This can be helpful for rendering dashboards outside of Entity Catalog. + * + * @public + */ +export const DashboardSnapshotList = newRelicDashboardPlugin.provide( + createComponentExtension({ + name: 'DashboardSnapshotList', + component: { + lazy: () => + import( + './components/NewRelicDashboard/DashboardSnapshotList/DashboardSnapshotList' + ).then(m => m.DashboardSnapshotList), + }, + }), +); diff --git a/plugins/playlist/README.md b/plugins/playlist/README.md index 25caa02742..1e81d07e56 100644 --- a/plugins/playlist/README.md +++ b/plugins/playlist/README.md @@ -154,6 +154,10 @@ playlist: ![Create New Playlist example](./docs/playlist-create-new.png) +### Duplicate Playlist Error + +![Duplicate Playlist Error example](./docs/playlist-duplicate-error.png) + ### Edit Existing Playlist ![Edit Existing Playlist example](./docs/playlist-edit-existing.png) @@ -166,6 +170,10 @@ playlist: ![Add to Playlist from Entity example](./docs/playlist-add-from-entity.png) +### Delete Playlist + +![Delete Playlist example](./docs/playlist-delete.png) + ## Links - [playlist-backend](../playlist-backend) provides the backend API for this frontend. diff --git a/plugins/playlist/docs/playlist-delete.png b/plugins/playlist/docs/playlist-delete.png new file mode 100644 index 0000000000..7e9ec7d996 Binary files /dev/null and b/plugins/playlist/docs/playlist-delete.png differ diff --git a/plugins/playlist/docs/playlist-duplicate-error.png b/plugins/playlist/docs/playlist-duplicate-error.png new file mode 100644 index 0000000000..8d2bec2588 Binary files /dev/null and b/plugins/playlist/docs/playlist-duplicate-error.png differ diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index 10be8ba6f8..274f9e21a1 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -205,6 +205,7 @@ describe('SearchModal', () => { const input = screen.getByLabelText('Search'); await userEvent.clear(input); + await 'a tick'; await userEvent.type(input, 'new term{enter}'); expect(navigate).toHaveBeenCalledWith('/search?query=new term'); diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md index 92f66c14b3..1e07c0fc69 100644 --- a/plugins/tech-insights/api-report.md +++ b/plugins/tech-insights/api-report.md @@ -68,6 +68,18 @@ export interface InsightFacts { // @public export const jsonRulesEngineCheckResultRenderer: CheckResultRenderer; +// @public (undocumented) +export const ScorecardInfo: (props: { + checkResults: CheckResult[]; + title: string; + description?: string | undefined; +}) => JSX_2.Element; + +// @public (undocumented) +export const ScorecardsList: (props: { + checkResults: CheckResult[]; +}) => JSX_2.Element; + // @public export interface TechInsightsApi { // (undocumented) diff --git a/plugins/tech-insights/src/index.ts b/plugins/tech-insights/src/index.ts index 9e075df038..e7659e39d4 100644 --- a/plugins/tech-insights/src/index.ts +++ b/plugins/tech-insights/src/index.ts @@ -17,6 +17,8 @@ export { techInsightsPlugin, EntityTechInsightsScorecardContent, EntityTechInsightsScorecardCard, + ScorecardInfo, + ScorecardsList, } from './plugin'; export { techInsightsApiRef, TechInsightsClient } from './api'; diff --git a/plugins/tech-insights/src/plugin.ts b/plugins/tech-insights/src/plugin.ts index 961519cd97..412d2a0a1d 100644 --- a/plugins/tech-insights/src/plugin.ts +++ b/plugins/tech-insights/src/plugin.ts @@ -42,6 +42,30 @@ export const techInsightsPlugin = createPlugin({ }, }); +/** + * @public + */ +export const ScorecardInfo = techInsightsPlugin.provide( + createRoutableExtension({ + name: 'ScorecardInfo', + component: () => + import('./components/ScorecardsInfo').then(m => m.ScorecardInfo), + mountPoint: rootRouteRef, + }), +); + +/** + * @public + */ +export const ScorecardsList = techInsightsPlugin.provide( + createRoutableExtension({ + name: 'ScorecardsList', + component: () => + import('./components/ScorecardsList').then(m => m.ScorecardsList), + mountPoint: rootRouteRef, + }), +); + /** * @public */ diff --git a/storybook/yarn.lock b/storybook/yarn.lock index e0f77cd510..91547eed81 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -2790,13 +2790,13 @@ __metadata: linkType: hard "@storybook/testing-library@npm:^0.2.0": - version: 0.2.1 - resolution: "@storybook/testing-library@npm:0.2.1" + version: 0.2.2 + resolution: "@storybook/testing-library@npm:0.2.2" dependencies: "@testing-library/dom": ^9.0.0 - "@testing-library/user-event": ~14.4.0 + "@testing-library/user-event": ^14.4.0 ts-dedent: ^2.2.0 - checksum: 2688361b634921219e4dc8e4acbc6622cfba6c224bd9bf17bf9bfb3655c906129cc82edd69354b9b1889b6f43c9c5e74bd51adb4407b68033d78279b93aee457 + checksum: 8ccdc1fbbb3472264c56b0aaf2f1c5d273f1ae9b230a53adf9cf82bf82c1a555550894f0e8869c206fa07b1fe8423da4d56590377756c58de3ec560b35a96c46 languageName: node linkType: hard @@ -2840,90 +2840,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-arm64@npm:1.3.90" +"@swc/core-darwin-arm64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-arm64@npm:1.3.92" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-x64@npm:1.3.90" +"@swc/core-darwin-x64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-x64@npm:1.3.92" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" +"@swc/core-linux-arm-gnueabihf@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.92" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" +"@swc/core-linux-arm64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" +"@swc/core-linux-arm64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" +"@swc/core-linux-x64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-musl@npm:1.3.90" +"@swc/core-linux-x64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-musl@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" +"@swc/core-win32-arm64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.92" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" +"@swc/core-win32-ia32-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.92" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" +"@swc/core-win32-x64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.92" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.90 - resolution: "@swc/core@npm:1.3.90" + version: 1.3.92 + resolution: "@swc/core@npm:1.3.92" dependencies: - "@swc/core-darwin-arm64": 1.3.90 - "@swc/core-darwin-x64": 1.3.90 - "@swc/core-linux-arm-gnueabihf": 1.3.90 - "@swc/core-linux-arm64-gnu": 1.3.90 - "@swc/core-linux-arm64-musl": 1.3.90 - "@swc/core-linux-x64-gnu": 1.3.90 - "@swc/core-linux-x64-musl": 1.3.90 - "@swc/core-win32-arm64-msvc": 1.3.90 - "@swc/core-win32-ia32-msvc": 1.3.90 - "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/core-darwin-arm64": 1.3.92 + "@swc/core-darwin-x64": 1.3.92 + "@swc/core-linux-arm-gnueabihf": 1.3.92 + "@swc/core-linux-arm64-gnu": 1.3.92 + "@swc/core-linux-arm64-musl": 1.3.92 + "@swc/core-linux-x64-gnu": 1.3.92 + "@swc/core-linux-x64-musl": 1.3.92 + "@swc/core-win32-arm64-msvc": 1.3.92 + "@swc/core-win32-ia32-msvc": 1.3.92 + "@swc/core-win32-x64-msvc": 1.3.92 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -2952,7 +2952,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab + checksum: 88c0c62ff790e896180862c341be8bae98baf0a5c5e87f2f04f49e14b8c4fba460d6b352618b4dda066c8ae6bf152cd843eab25837f38128175208b8c0635721 languageName: node linkType: hard @@ -2986,12 +2986,12 @@ __metadata: languageName: node linkType: hard -"@testing-library/user-event@npm:~14.4.0": - version: 14.4.3 - resolution: "@testing-library/user-event@npm:14.4.3" +"@testing-library/user-event@npm:^14.4.0": + version: 14.5.1 + resolution: "@testing-library/user-event@npm:14.5.1" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 852c48ea6db1c9471b18276617c84fec4320771e466cd58339a732ca3fd73ad35e5a43ae14f51af51a8d0a150dcf60fcaab049ef367871207bea8f92c4b8195e + checksum: 3e6bc9fd53dfe2f3648190193ed2fd4bca2a1bfb47f68810df3b33f05412526e5fd5c4ef9dc5375635e0f4cdf1859916867b597eed22bda1321e04242ea6c519 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 38af62fcd1..09ffcf2458 100644 --- a/yarn.lock +++ b/yarn.lock @@ -200,8 +200,8 @@ __metadata: linkType: hard "@apollo/server@npm:^4.0.0": - version: 4.9.3 - resolution: "@apollo/server@npm:4.9.3" + version: 4.9.4 + resolution: "@apollo/server@npm:4.9.4" dependencies: "@apollo/cache-control-types": ^1.0.3 "@apollo/server-gateway-interface": ^1.1.1 @@ -231,7 +231,7 @@ __metadata: whatwg-mimetype: ^3.0.0 peerDependencies: graphql: ^16.6.0 - checksum: 28537d7646669a5dc1302cfd75d8a9bf473459ee585c6b778d174628a2cfb3f89a5ac742eca7de2a779b6c9e3f30da509a8787a71227520d009ac190aa7a9207 + checksum: bf7105ffceaed6e3c54f1506513944bb324ae32e92b1aabb3ec7de1b9fee1373bdec6e1a3f5efb7c7f8090671f1ba2d37c01f5b1456c93127ffede1a0b554bac languageName: node linkType: hard @@ -3305,12 +3305,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.15, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.22.15 - resolution: "@babel/runtime@npm:7.22.15" +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.1, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.23.1 + resolution: "@babel/runtime@npm:7.23.1" dependencies: regenerator-runtime: ^0.14.0 - checksum: 793296df1e41599a935a3d77ec01eb6088410d3fd4dbe4e92f06c6b7bb2f8355024e6d78621a3a35f44e0e23b0b59107f23d585384df4f3123256a1e1492040e + checksum: 0cd0d43e6e7dc7f9152fda8c8312b08321cda2f56ef53d6c22ebdd773abdc6f5d0a69008de90aa41908d00e2c1facb24715ff121274e689305c858355ff02c70 languageName: node linkType: hard @@ -4313,6 +4313,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" + "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.4 "@material-ui/icons": ^4.11.3 "@testing-library/jest-dom": ^5.10.1 @@ -7351,38 +7352,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home@npm:^0.5.8": - version: 0.5.8 - resolution: "@backstage/plugin-home@npm:0.5.8" - dependencies: - "@backstage/catalog-model": ^1.4.2 - "@backstage/config": ^1.1.0 - "@backstage/core-components": ^0.13.5 - "@backstage/core-plugin-api": ^1.6.0 - "@backstage/plugin-catalog-react": ^1.8.4 - "@backstage/plugin-home-react": ^0.1.3 - "@backstage/theme": ^0.4.2 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@rjsf/core-v5": "npm:@rjsf/core@5.13.0" - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0" - "@rjsf/utils": 5.13.0 - "@rjsf/validator-ajv8": 5.13.0 - "@types/react": ^16.13.1 || ^17.0.0 - lodash: ^4.17.21 - react-grid-layout: ^1.3.4 - react-resizable: ^3.0.4 - react-use: ^17.2.4 - zod: ^3.21.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 4f895b3a7e7f61149ba7b8fd6ec998d1f83b6e5262073893c5863fe79c46e5e2f52b43346f310733e04815aaebd82b8a13d34616e8d0848f60f87b1fb3193d60 - languageName: node - linkType: hard - "@backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": version: 0.0.0-use.local resolution: "@backstage/plugin-home@workspace:plugins/home" @@ -10535,13 +10504,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.21.0 - resolution: "@codemirror/view@npm:6.21.0" + version: 6.21.2 + resolution: "@codemirror/view@npm:6.21.2" dependencies: "@codemirror/state": ^6.1.4 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: da49d5541b137a812e1837709130b9a4502fac71b87c45d45384116a7a2b1dab556c283abb673946ba9d044a640ab9058727b85de9b7b576c44848dfbf0ed7bb + checksum: d972a32f26882a1811ffab833f8705339cd4c1bfe56765ed6ecbc1d84466b71a728adb8f4b4fc566ca3bccee5aacd2585e79cb96a851dcd48777e2320dab1892 languageName: node linkType: hard @@ -13414,14 +13383,14 @@ __metadata: languageName: node linkType: hard -"@mui/base@npm:5.0.0-beta.17": - version: 5.0.0-beta.17 - resolution: "@mui/base@npm:5.0.0-beta.17" +"@mui/base@npm:5.0.0-beta.18": + version: 5.0.0-beta.18 + resolution: "@mui/base@npm:5.0.0-beta.18" dependencies: - "@babel/runtime": ^7.22.15 + "@babel/runtime": ^7.23.1 "@floating-ui/react-dom": ^2.0.2 - "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.11 + "@mui/types": ^7.2.5 + "@mui/utils": ^5.14.12 "@popperjs/core": ^2.11.8 clsx: ^2.0.0 prop-types: ^15.8.1 @@ -13432,27 +13401,27 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 96ffb85864fc796783514e089c0011ebcc5174705082dc98197ab035dfb287427069c0338e662a4680951849dfbe7a5231f4f6f2aee710af05c07e8578f93310 + checksum: 7d4ca1e9d537b7b5850567f1adecd1caa47b8613b43a587cf2f399cfda0a8c17dfda06b030c0bea554b76abe7ac25bb9b1af3c996574def5f860cda0c6ea4a3c languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.14.11": - version: 5.14.11 - resolution: "@mui/core-downloads-tracker@npm:5.14.11" - checksum: f3e7594c93d4cf5e3649336eef2b57842c171f3deb6890c03be7eccb88d3ac276aac1ab3ad409d124d16468314018778e2dbb92a62ac34c7f44b2813c47f29fb +"@mui/core-downloads-tracker@npm:^5.14.12": + version: 5.14.12 + resolution: "@mui/core-downloads-tracker@npm:5.14.12" + checksum: 1c1576ceecf7cade9e0d7a531632f5f9db24853d9ebbd47bb9ed943a3af7de734ad4f3374bab79880e9591db3ea55ea84cc10df72177f9ca5e32cc7662e04405 languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.14.11 - resolution: "@mui/material@npm:5.14.11" + version: 5.14.12 + resolution: "@mui/material@npm:5.14.12" dependencies: - "@babel/runtime": ^7.22.15 - "@mui/base": 5.0.0-beta.17 - "@mui/core-downloads-tracker": ^5.14.11 - "@mui/system": ^5.14.11 - "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.11 + "@babel/runtime": ^7.23.1 + "@mui/base": 5.0.0-beta.18 + "@mui/core-downloads-tracker": ^5.14.12 + "@mui/system": ^5.14.12 + "@mui/types": ^7.2.5 + "@mui/utils": ^5.14.12 "@types/react-transition-group": ^4.4.6 clsx: ^2.0.0 csstype: ^3.1.2 @@ -13472,16 +13441,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 350d642773d4b19d5b9deac956203dafe89cd005ba8cd6017d1ab0e97ba45ca230050249f34a17f0f00efe466162d47487f160159bebe3e52af1b34dd28579d0 + checksum: a0d3b52ce3cc282da04036db0805f95f27b35a9c899f132f962fe96f05d3eb112e99ccbf6bd9d05cae617b24beda95470aedaff129d6e39d1b52e1ddf80a9e12 languageName: node linkType: hard -"@mui/private-theming@npm:^5.14.11": - version: 5.14.11 - resolution: "@mui/private-theming@npm:5.14.11" +"@mui/private-theming@npm:^5.14.12": + version: 5.14.12 + resolution: "@mui/private-theming@npm:5.14.12" dependencies: - "@babel/runtime": ^7.22.15 - "@mui/utils": ^5.14.11 + "@babel/runtime": ^7.23.1 + "@mui/utils": ^5.14.12 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -13489,15 +13458,15 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: a5d461ae9679b1f3b79f529c51c055e03d84421812bb12110d735fbc5528ae188900488b32aa1b860cb978ac6dd0cb9f54a10e2ff214e853e969ef5c1ed87e84 + checksum: f8127347dc29126fece3b530cb156f6ababf747b64bb1c712874375e6efae6c738c014304d9553001d67a59b24ca6a665f2d03bb5ae137f03bdba90815f0ecc1 languageName: node linkType: hard -"@mui/styled-engine@npm:^5.14.11": - version: 5.14.11 - resolution: "@mui/styled-engine@npm:5.14.11" +"@mui/styled-engine@npm:^5.14.12": + version: 5.14.12 + resolution: "@mui/styled-engine@npm:5.14.12" dependencies: - "@babel/runtime": ^7.22.15 + "@babel/runtime": ^7.23.1 "@emotion/cache": ^11.11.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13510,19 +13479,19 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: 0a593f967ab56c32c611eae4a83bc23c4ab3a8931e76a6e553ed18230c2f4e9e912d519fe2f0a24970ff154c198634903f134eb54f00ceebde138a73b953622f + checksum: c689ccad59e7fd54cd8367838612daa4f132c64d8c6b99ccb7c8f9697b5c940a6bf7edcccd686ce437b565dbcf3bfc12bb0dea47cbd5fbd750ea1553017f9c0d languageName: node linkType: hard -"@mui/system@npm:^5.14.11": - version: 5.14.11 - resolution: "@mui/system@npm:5.14.11" +"@mui/system@npm:^5.14.12": + version: 5.14.12 + resolution: "@mui/system@npm:5.14.12" dependencies: - "@babel/runtime": ^7.22.15 - "@mui/private-theming": ^5.14.11 - "@mui/styled-engine": ^5.14.11 - "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.11 + "@babel/runtime": ^7.23.1 + "@mui/private-theming": ^5.14.12 + "@mui/styled-engine": ^5.14.12 + "@mui/types": ^7.2.5 + "@mui/utils": ^5.14.12 clsx: ^2.0.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13538,28 +13507,28 @@ __metadata: optional: true "@types/react": optional: true - checksum: c3d0e1a09a9638663a6467452a7725593e9de6f9620e199add1080db42a7affaca39f52a1b6a52fb75d708f3e30336946babb2a8d1d43fab81c6a1fe3e420b21 + checksum: 70c3920eadc593395a2d258ddea0f3b28689c7f02fdaf97fc205e16efaeebe462b2ab01c69a20a3bcb011e0d07ea47fa66a433e70d0a1ce15d7b694fb3c52135 languageName: node linkType: hard -"@mui/types@npm:^7.2.4": - version: 7.2.4 - resolution: "@mui/types@npm:7.2.4" +"@mui/types@npm:^7.2.5": + version: 7.2.5 + resolution: "@mui/types@npm:7.2.5" peerDependencies: - "@types/react": "*" + "@types/react": ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 16bea0547492193a22fd1794382f314698a114f6c673825314c66b56766c3a9d305992cc495684722b7be16a1ecf7e6e48a79caa64f90c439b530e8c02611a61 + checksum: 2807e9a8eb251294eee6384a4d68b2159f7660466625f1781e9efea282aa7c6ff35b42bc7039c2d43e7a5ac80291dcb85c4110022b0b6de4e12b6406b62f3dc1 languageName: node linkType: hard -"@mui/utils@npm:^5.14.11": - version: 5.14.11 - resolution: "@mui/utils@npm:5.14.11" +"@mui/utils@npm:^5.14.12": + version: 5.14.12 + resolution: "@mui/utils@npm:5.14.12" dependencies: - "@babel/runtime": ^7.22.15 - "@types/prop-types": ^15.7.5 + "@babel/runtime": ^7.23.1 + "@types/prop-types": ^15.7.7 prop-types: ^15.8.1 react-is: ^18.2.0 peerDependencies: @@ -13568,7 +13537,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 84e640dea3589ea7edb7d8f33748d83d561d4ef413c4d3e2216ddf9c0842d8b04d162e3fa5ea59f03846934f17fb446ed8464e318dd4e2e299e3b44b06637d76 + checksum: 41470b6292b7a46c71fb0a0acc6a5f05a5e080648106b8805555de920e8f748669c7e8d39cbbcf0f52be9053927bb8439a748e24bd02bc1a220c9bded4435f42 languageName: node linkType: hard @@ -14830,14 +14799,14 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-github-pull-requests@npm:^2.2.7": - version: 2.5.16 - resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.16" + version: 2.5.17 + resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.17" dependencies: "@backstage/catalog-model": ^1.4.2 "@backstage/core-components": ^0.13.5 "@backstage/core-plugin-api": ^1.6.0 "@backstage/plugin-catalog-react": ^1.8.4 - "@backstage/plugin-home": ^0.5.8 + "@backstage/plugin-home-react": ^0.1.3 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 @@ -14854,7 +14823,7 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: cb35e64d4df6f81829cd238e3b06b84453ad9231a30a0a4698ebb9d408445af0bfeb59d27bcc5d818013735f2f4d44a89ff9824258ff1565274c524c3ae905cc + checksum: 4a2203aad37ae8b268f3ff11967545bbcfc18741f3e3ea0e7106dcbb3f8af47a7701ebdcdf17e80023590394fb2f923e0f3691b7d0334586892f99335756a47d languageName: node linkType: hard @@ -14934,18 +14903,18 @@ __metadata: linkType: hard "@rollup/plugin-yaml@npm:^4.0.0": - version: 4.1.1 - resolution: "@rollup/plugin-yaml@npm:4.1.1" + version: 4.1.2 + resolution: "@rollup/plugin-yaml@npm:4.1.2" dependencies: "@rollup/pluginutils": ^5.0.1 js-yaml: ^4.1.0 tosource: ^2.0.0-alpha.3 peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - checksum: 99c8f9d4a354056bec8a9398786777203d87db32db0cad681f65ee896cbbbb8a61ace0b1c3d801622782ccf28e56eac6cdde950541fb1f7b3e651ad9c705d5c3 + checksum: a044bb4568a10712465553ea5f31c13a2b7bc371a7f8382014e6b8048c0a264f5645f83f4d70ce9ab46b75117b94cdc032b597e9315fd2adcd8f30637f44bbea languageName: node linkType: hard @@ -16542,90 +16511,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-arm64@npm:1.3.90" +"@swc/core-darwin-arm64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-arm64@npm:1.3.92" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-darwin-x64@npm:1.3.90" +"@swc/core-darwin-x64@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-darwin-x64@npm:1.3.92" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" +"@swc/core-linux-arm-gnueabihf@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.92" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" +"@swc/core-linux-arm64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" +"@swc/core-linux-arm64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.92" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" +"@swc/core-linux-x64-gnu@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-linux-x64-musl@npm:1.3.90" +"@swc/core-linux-x64-musl@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-linux-x64-musl@npm:1.3.92" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" +"@swc/core-win32-arm64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.92" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" +"@swc/core-win32-ia32-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.92" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.90": - version: 1.3.90 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" +"@swc/core-win32-x64-msvc@npm:1.3.92": + version: 1.3.92 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.92" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.90 - resolution: "@swc/core@npm:1.3.90" + version: 1.3.92 + resolution: "@swc/core@npm:1.3.92" dependencies: - "@swc/core-darwin-arm64": 1.3.90 - "@swc/core-darwin-x64": 1.3.90 - "@swc/core-linux-arm-gnueabihf": 1.3.90 - "@swc/core-linux-arm64-gnu": 1.3.90 - "@swc/core-linux-arm64-musl": 1.3.90 - "@swc/core-linux-x64-gnu": 1.3.90 - "@swc/core-linux-x64-musl": 1.3.90 - "@swc/core-win32-arm64-msvc": 1.3.90 - "@swc/core-win32-ia32-msvc": 1.3.90 - "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/core-darwin-arm64": 1.3.92 + "@swc/core-darwin-x64": 1.3.92 + "@swc/core-linux-arm-gnueabihf": 1.3.92 + "@swc/core-linux-arm64-gnu": 1.3.92 + "@swc/core-linux-arm64-musl": 1.3.92 + "@swc/core-linux-x64-gnu": 1.3.92 + "@swc/core-linux-x64-musl": 1.3.92 + "@swc/core-win32-arm64-msvc": 1.3.92 + "@swc/core-win32-ia32-msvc": 1.3.92 + "@swc/core-win32-x64-msvc": 1.3.92 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -16654,7 +16623,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab + checksum: 88c0c62ff790e896180862c341be8bae98baf0a5c5e87f2f04f49e14b8c4fba460d6b352618b4dda066c8ae6bf152cd843eab25837f38128175208b8c0635721 languageName: node linkType: hard @@ -17703,11 +17672,11 @@ __metadata: linkType: hard "@types/jquery@npm:^3.3.34": - version: 3.5.20 - resolution: "@types/jquery@npm:3.5.20" + version: 3.5.21 + resolution: "@types/jquery@npm:3.5.21" dependencies: "@types/sizzle": "*" - checksum: 9bd69faea3d60f52d3029a87b890003042a9dcf4f538c23ac2c11b3bd0e0ccd86b281d5ba3028d1b02df67c69266b8dc0ef0a35696ae174515ecf34523a0287b + checksum: 48cce8892f0292ac68853677d408195436a460ed45445a2da13deddcf21b407b3f896bbf5714f320c8f44666fdff5ceba5c59e873a316486098040404dcf56f4 languageName: node linkType: hard @@ -18012,9 +17981,9 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1": - version: 20.6.5 - resolution: "@types/node@npm:20.6.5" - checksum: b849e849cf7631458a65c5019c81962028e306d8c4455a48422277b240f5a7eb8a1f1dafa60306bd4c773b77263bb8b05c074b1026e868bd137bb2022cf63ea2 + version: 20.8.2 + resolution: "@types/node@npm:20.8.2" + checksum: 3da73e25d821bfcdb7de98589027e08bb4848e55408671c4a83ec0341e124b5313a0b20e1e4b4eff1168ea17a86f622ad73fcb04b761abd77496b9a27cbd5de5 languageName: node linkType: hard @@ -18033,16 +18002,16 @@ __metadata: linkType: hard "@types/node@npm:^16.11.26, @types/node@npm:^16.9.2": - version: 16.18.54 - resolution: "@types/node@npm:16.18.54" - checksum: 208e8fc64f605e9cd55ab5e620a0fd019d8fe5629e3e3c5de869a149b731ab0fac5720c516dccc0ecc834ac27df754723dfe6554551663f016ba5096ea8851df + version: 16.18.57 + resolution: "@types/node@npm:16.18.57" + checksum: db21a14416de3abce8dfc30d9e9513c505060ef4d197fdc1b1b7374feca3417a7757172d041989fd49910245e9f2d7869201accac3cceee7c75bfdf8759ead6d languageName: node linkType: hard "@types/node@npm:^18.11.17, @types/node@npm:^18.17.8": - version: 18.17.18 - resolution: "@types/node@npm:18.17.18" - checksum: 59cbd906363d37017fe9ba0c08c1446e440d4d977459609c5f90b8fb7eb41f273ce8af30c5a5b5d599d7de934c1b3702bc9fc27caf8d2270e5cdb659c5232991 + version: 18.18.3 + resolution: "@types/node@npm:18.18.3" + checksum: ed97a832179e0cfbb93738021fe16d0bc5c0f34bea35269c23c9dd5f0ecc8be93dbe5efd51630189a099b31786a47c1bde115508831a7245613a55c3ad1a7d6b languageName: node linkType: hard @@ -18203,7 +18172,7 @@ __metadata: languageName: node linkType: hard -"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.3, @types/prop-types@npm:^15.7.5": +"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.3, @types/prop-types@npm:^15.7.7": version: 15.7.8 resolution: "@types/prop-types@npm:15.7.8" checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae @@ -18613,11 +18582,11 @@ __metadata: linkType: hard "@types/supertest@npm:^2.0.12, @types/supertest@npm:^2.0.8": - version: 2.0.13 - resolution: "@types/supertest@npm:2.0.13" + version: 2.0.14 + resolution: "@types/supertest@npm:2.0.14" dependencies: "@types/superagent": "*" - checksum: fe66be8e16626f254dc9d9691706942689f47a84edf7d3baaeadd6d4d576dbf915ee70cebdd7034015e83fa91fcd2dcff1cd0252514e4c510619817a183b5b4f + checksum: 9f6850a22b8f0fd4c26a6dfd9b64771a66476b1a4f841a3b84a9da843ce69463efbf37594fe107297dd14a225d199b802464d48d70e9413238c637903d392137 languageName: node linkType: hard @@ -19035,9 +19004,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.21.18": - version: 4.21.18 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.18" +"@uiw/codemirror-extensions-basic-setup@npm:4.21.19": + version: 4.21.19 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.19" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/commands": ^6.0.0 @@ -19054,19 +19023,19 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: c643eebc45e2067080c46e28fdb4ac40043e5890f4862bd45fe5bf816894b6c118ea901ca9ba1dce8862877622ebd793db6ec220491506355ed562a0dc0c4507 + checksum: 85a1f8b3e071b4587f13609d8449406baa8dead51aa588b914ffa95aac1bdfe1e1aa78689d7927fb90a554b747409cc59cada18fcbe2c204f5936e5441fbade1 languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.9.3": - version: 4.21.18 - resolution: "@uiw/react-codemirror@npm:4.21.18" + version: 4.21.19 + resolution: "@uiw/react-codemirror@npm:4.21.19" dependencies: "@babel/runtime": ^7.18.6 "@codemirror/commands": ^6.1.0 "@codemirror/state": ^6.1.1 "@codemirror/theme-one-dark": ^6.0.0 - "@uiw/codemirror-extensions-basic-setup": 4.21.18 + "@uiw/codemirror-extensions-basic-setup": 4.21.19 codemirror: ^6.0.0 peerDependencies: "@babel/runtime": ">=7.11.0" @@ -19076,7 +19045,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: ef3897e9901b98fd981d4b9db2ae8702aa7ffda4cf5cab3286963580606a6dde38e77a4314c12574b6f5f251d62b62e59f0a1a445009b5927b8500f4b5fd795c + checksum: bcd016ac806ff34ab3ab16e17090c80c0ed7f835835575c7a15b21238cae9169662444323cbbc8ef2a62c5e8fd7d8b668fd3562cf79b509ededaf7cd4970adf0 languageName: node linkType: hard @@ -20299,13 +20268,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0": - version: 1.5.0 - resolution: "axios@npm:1.5.0" + version: 1.5.1 + resolution: "axios@npm:1.5.1" dependencies: follow-redirects: ^1.15.0 form-data: ^4.0.0 proxy-from-env: ^1.1.0 - checksum: e7405a5dbbea97760d0e6cd58fecba311b0401ddb4a8efbc4108f5537da9b3f278bde566deb777935a960beec4fa18e7b8353881f2f465e4f2c0e949fead35be + checksum: 4444f06601f4ede154183767863d2b8e472b4a6bfc5253597ed6d21899887e1fd0ee2b3de792ac4f8459fe2e359d2aa07c216e45fd8b9e4e0688a6ebf48a5a8d languageName: node linkType: hard @@ -20666,13 +20635,13 @@ __metadata: linkType: hard "better-sqlite3@npm:^8.0.0": - version: 8.6.0 - resolution: "better-sqlite3@npm:8.6.0" + version: 8.7.0 + resolution: "better-sqlite3@npm:8.7.0" dependencies: bindings: ^1.5.0 node-gyp: latest prebuild-install: ^7.1.1 - checksum: 9ebdfd675352347cda1ba30d620a3c512d9db827a1eba66460fd48203a7ad8138b0195893bbf47d40f704bcdd598710041271d4ed69779979b6f784c0d3579a1 + checksum: f1fa38a9a0e4fcd59ececb67c60371b9638d29c19ce9af034421e8a56c9a77e799bb1411b1c3cb08bb9678e15dfb8985553a9ef4098cf5558e7207a3e019f211 languageName: node linkType: hard @@ -31214,18 +31183,18 @@ __metadata: linkType: hard "libsodium-wrappers@npm:^0.7.11": - version: 0.7.11 - resolution: "libsodium-wrappers@npm:0.7.11" + version: 0.7.13 + resolution: "libsodium-wrappers@npm:0.7.13" dependencies: - libsodium: ^0.7.11 - checksum: 6a6ef47b2213e3fb4687196c28fee4c9885f70d89547d845e62d96014d3d5ad9f59cb05fadc601debc0031a3cfd0b9b416d7efbeb5bf66db6aa0ed69f55a6293 + libsodium: ^0.7.13 + checksum: d184395f7c33023414b191ef9ea2171eb1a5cb061503e886ea877590cb7adc3a4feaf794b9b08731a20515518fa23dbf1c1bfcd376e5ab01728e95cf1cb7525a languageName: node linkType: hard -"libsodium@npm:^0.7.11": - version: 0.7.11 - resolution: "libsodium@npm:0.7.11" - checksum: 0a3493ac1829d1e346178b6984c4eb449dc77157c906876441386c0c653142e3fa56f623ce980bb50e580196578689298c9cd406ce6d514904090e370c6bc0f7 +"libsodium@npm:^0.7.13": + version: 0.7.13 + resolution: "libsodium@npm:0.7.13" + checksum: 75a5f70e84c197d54d9b67dcbd852abbd41cca8facd510767c7c8400a52a23da293e83eebf1693831b2c0c0498f266bd9350a8c27ec66f46a055890dff758d38 languageName: node linkType: hard @@ -35829,13 +35798,13 @@ __metadata: linkType: hard "postcss@npm:^8.1.0, postcss@npm:^8.4.21": - version: 8.4.29 - resolution: "postcss@npm:8.4.29" + version: 8.4.31 + resolution: "postcss@npm:8.4.31" dependencies: nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: dd6daa25e781db9ae5b651d9b7bfde0ec6e60e86a37da69a18eb4773d5ddd51e28fc4ff054fbdc04636a31462e6bf09a1e50986f69ac52b10d46b7457cd36d12 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard @@ -43250,9 +43219,9 @@ __metadata: linkType: hard "zod@npm:^3.21.4": - version: 3.22.3 - resolution: "zod@npm:3.22.3" - checksum: 65b05139be337078a70700b05942ab7f2ef5f11abe194df14ef257fac4e5c383476a4dc290731842996bd57fc8d5bf38e5a4c907fe8cdf8b15477f8da5bfcc00 + version: 3.22.4 + resolution: "zod@npm:3.22.4" + checksum: 80bfd7f8039b24fddeb0718a2ec7c02aa9856e4838d6aa4864335a047b6b37a3273b191ef335bf0b2002e5c514ef261ffcda5a589fb084a48c336ffc4cdbab7f languageName: node linkType: hard