diff --git a/.changeset/tasty-jobs-help.md b/.changeset/tasty-jobs-help.md new file mode 100644 index 0000000000..ad1df8fb8c --- /dev/null +++ b/.changeset/tasty-jobs-help.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-graphql-voyager': minor +--- + +Add the new GraphQL Voyager tool as a plugin for backstage, expose necessary API and components needed for it. + +For more information on how to use this plugin and configure it, please navigate to the [README](https://github.com/backstage/backstage/tree/master/plugins/graphql-voyager/README.md) of the plugin. diff --git a/microsite/data/plugins/graphql-voyager.yaml b/microsite/data/plugins/graphql-voyager.yaml new file mode 100644 index 0000000000..c6ebf5e412 --- /dev/null +++ b/microsite/data/plugins/graphql-voyager.yaml @@ -0,0 +1,13 @@ +--- +title: GraphQL Voyager +author: PostNL +authorUrl: https://github.com/postnl +category: Debugging +description: Integrates the GraphQL Voyager tool inside Backstage as a plugin. +documentation: https://github.com/backstage/backstage/tree/master/plugins/graphql-voyager +iconUrl: https://res.cloudinary.com/apideck/image/upload/v1612724234/icons/graphql-voyager.png +npmPackageName: '@backstage/plugin-graphql-voyager' +tags: + - graphql + - graphql-voyager +addedDate: '2023-01-27' diff --git a/plugins/graphql-voyager/.eslintrc.js b/plugins/graphql-voyager/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/graphql-voyager/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/graphql-voyager/README.md b/plugins/graphql-voyager/README.md new file mode 100644 index 0000000000..2c903cd9e5 --- /dev/null +++ b/plugins/graphql-voyager/README.md @@ -0,0 +1,76 @@ +# graphql-voyager + +Welcome to the graphql-voyager plugin! + +Presents a graph structure of your entire GraphQL API, with tabs for multiple API urls: +![](./src/assets/plugin.png) + +## Getting started + +### Installing + +To get started, first install the plugin with the following command: + +```bash +# From your Backstage root directory +yarn add --cwd packages/app @backstage/plugin-graphql-voyager +``` + +### Adding the page + +In order to be able to navigate to the graphQL voyager page, a new route needs to be added to the app. This can be done in the following way: + +```tsx +// packages/app/App.tsx + + import { GraphQLVoyagerPage } from '@backstage/plugin-graphql-voyager'; + + const routes = ( + + }/> +``` + +### Configuration + +In order for the plugin to function correctly. GraphQL endpoints need to be added / configured through the GraphQLVoyager API. This can be done by implementing the `graphQlVoyagerApiRef` exported by this plugin. + +Add your own configuration to the `packages/app/src/apis.ts` file the following way: + +```ts +import { identityApiRef } from '@backstage/core-plugin-api'; +import { GraphQLVoyagerEndpoints } from '@backstage/plugin-graphql-voyager'; + +export const apis: AnyApiFactory[] = [ + createApiFactory({ + api: graphQlVoyagerApiRef, + deps: { identityApi: identityApiRef }, + factory: ({ identityApiRef }) => { + return GraphQLVoyagerEndpoints.from([ + { + id: `graphql-voyager-endpoint-id`, + title: 'endpoint-title', + introspectionErrorMessage: + 'Unable to perform introspection, make sure you are on the correct environment.', + introspection: async (query: any) => { + const token = 'someSecretJWTComingFromIdentityApiRef'; + + const res = await fetch('graphQLEndpoint', { + method: 'POST', + body: JSON.stringify({ query }), + headers: { + 'Content-Type': 'application/json', + Authorization: token, + }, + }); + + return res.json(); + }, + voyagerProps: { + hideDocs: true, + }, + }, + ]); + }, + }), +]; +``` diff --git a/plugins/graphql-voyager/api-report.md b/plugins/graphql-voyager/api-report.md new file mode 100644 index 0000000000..9b488f9356 --- /dev/null +++ b/plugins/graphql-voyager/api-report.md @@ -0,0 +1,71 @@ +## API Report File for "@backstage/plugin-graphql-voyager" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { ApiRef } from '@backstage/core-plugin-api'; +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { VoyagerDisplayOptions } from 'graphql-voyager/typings/components/Voyager'; +import { WorkerCallback } from 'graphql-voyager/typings/utils/types'; + +// @public (undocumented) +export type GraphQLVoyagerApi = { + getEndpoints(): Promise; +}; + +// @public (undocumented) +export const graphQlVoyagerApiRef: ApiRef; + +// @public (undocumented) +export type GraphQLVoyagerEndpoint = { + id: string; + title: string; + introspection: (body: any) => Promise; + introspectionErrorMessage: string; + voyagerProps?: { + displayOptions?: VoyagerDisplayOptions; + hideDocs?: boolean; + hideSettings?: boolean; + workerURI?: string; + loadWorker?: WorkerCallback; + }; +}; + +// @public (undocumented) +export class GraphQLVoyagerEndpoints implements GraphQLVoyagerApi { + // (undocumented) + static from(endpoints: GraphQLVoyagerEndpoint[]): GraphQLVoyagerEndpoints; + // (undocumented) + getEndpoints(): Promise; +} + +// @public (undocumented) +export const GraphqlVoyagerPage: ( + props: GraphQLVoyagerPageProps, +) => JSX.Element; + +// @public (undocumented) +export type GraphQLVoyagerPageProps = { + title?: string; +}; + +// @public (undocumented) +export const graphqlVoyagerPlugin: BackstagePlugin< + { + root: RouteRef; + }, + {}, + {} +>; + +// @public (undocumented) +export const introspectionQuery: string; + +// @public (undocumented) +export const Router: (props: GraphQLVoyagerPageProps) => JSX.Element; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json new file mode 100644 index 0000000000..02e8ec95ca --- /dev/null +++ b/plugins/graphql-voyager/package.json @@ -0,0 +1,53 @@ +{ + "name": "@backstage/plugin-graphql-voyager", + "description": "Backstage plugin for GraphQL Voyager", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.57", + "graphql-voyager": "^1.0.0-rc.31", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.49.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/graphql-voyager/src/assets/plugin.png b/plugins/graphql-voyager/src/assets/plugin.png new file mode 100644 index 0000000000..602c7abde3 Binary files /dev/null and b/plugins/graphql-voyager/src/assets/plugin.png differ diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.test.tsx b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.test.tsx new file mode 100644 index 0000000000..76ccbd9965 --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.test.tsx @@ -0,0 +1,94 @@ +/* + * 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 React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { GraphQLVoyagerBrowser } from './GraphQLVoyagerBrowser'; + +jest.mock('graphql-voyager', () => ({ Voyager: () => '' })); + +describe('GraphQLVoyagerBrowser', () => { + it('should render error text if there are no endpoints', async () => { + const rendered = await renderInTestApp( + , + ); + + expect(rendered.getByText('No endpoints available')).toBeInTheDocument(); + }); + + it('should render endpoint tabs', async () => { + const rendered = await renderInTestApp( + , + ); + + expect(rendered.getByText('Endpoint A')).toBeInTheDocument(); + expect(rendered.getByText('Endpoint B')).toBeInTheDocument(); + }); + + it('Should render the introspection error message when introspection fails', async () => { + const rendered = await renderInTestApp( + , + ); + + expect(rendered.getByText('Failed to introspect A')).toBeInTheDocument(); + }); +}); diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx new file mode 100644 index 0000000000..d2f9262983 --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx @@ -0,0 +1,107 @@ +/* + * 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 { + GraphQLVoyagerEndpoint, + introspectionQuery, +} from '../../lib/api/types'; +import { useState } from 'react'; +import { makeStyles, Tab, Tabs, Typography } from '@material-ui/core'; +import React, { Suspense } from 'react'; +import { BackstageTheme } from '@backstage/theme'; +import { Content, ErrorPanel, Progress } from '@backstage/core-components'; +import { Voyager } from 'graphql-voyager'; +import useAsync from 'react-use/lib/useAsync'; + +const useStyles = makeStyles(() => ({ + root: { + height: '100%', + display: 'flex', + flexFlow: 'column nowrap', + }, +})); + +type GraphQLVoyagerBrowserProps = { + endpoints: GraphQLVoyagerEndpoint[]; +}; + +const NoEndpoints = () => { + return No endpoints available; +}; + +const VoyagerBrowserContent = ({ + endpoint, +}: { + endpoint: GraphQLVoyagerEndpoint; +}) => { + const { id, introspection, introspectionErrorMessage, voyagerProps } = + endpoint; + const { value, loading, error } = useAsync( + () => introspection(introspectionQuery), + [endpoint], + ); + + if (loading) { + return ; + } else if (error) { + return ; + } + return value.data ? ( + + ) : ( + + {introspectionErrorMessage} + + ); +}; + +const VoyagerBrowser = (props: GraphQLVoyagerBrowserProps) => { + const { endpoints } = props; + const [tabIndex, setTabIndex] = useState(0); + const classes = useStyles(); + + return ( +
+ }> + setTabIndex(value)} + indicatorColor="primary" + > + {endpoints.map(({ title, id }, index) => ( + + ))} + + + + + +
+ ); +}; + +/** @public */ +export const GraphQLVoyagerBrowser = (props: GraphQLVoyagerBrowserProps) => { + const hasEndpoints = checkEndpoints(props); + + if (!hasEndpoints) { + return ; + } + return ; +}; + +function checkEndpoints(props: GraphQLVoyagerBrowserProps) { + return props.endpoints.length; +} diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/index.ts b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/index.ts new file mode 100644 index 0000000000..3beb0ccd95 --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './GraphQLVoyagerBrowser'; diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.test.tsx b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.test.tsx new file mode 100644 index 0000000000..67c257be2b --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.test.tsx @@ -0,0 +1,60 @@ +/* + * 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 React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; + +import { GraphQLVoyagerPage } from './GraphQLVoyagerPage'; +import { GraphQLVoyagerApi, graphQlVoyagerApiRef } from '../../lib/api'; + +jest.mock('../GraphQLVoyagerBrowser', () => ({ + GraphQLVoyagerBrowser: () => '', +})); + +describe('GraphQLVoyagerPage', () => { + it('should show error when no endpoints are loaded', async () => { + const loadingApi: GraphQLVoyagerApi = { + async getEndpoints() { + throw new Error('No endpoints'); + }, + }; + + const rendered = await renderInTestApp( + + + , + ); + + expect(rendered.getByText('Welcome to Voyager!')).toBeInTheDocument(); + expect(rendered.getByText('Error: No endpoints')).toBeInTheDocument(); + }); + + it('should show GraphQLVoyagerBrowser', async () => { + const loadingApi: GraphQLVoyagerApi = { + async getEndpoints() { + return []; + }, + }; + + const rendered = await renderInTestApp( + + + , + ); + + expect(rendered.getByText('Welcome to Voyager!')).toBeInTheDocument(); + expect(rendered.getByText('')).toBeInTheDocument(); + }); +}); diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.tsx b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.tsx new file mode 100644 index 0000000000..f3c4f70b4f --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/GraphQLVoyagerPage.tsx @@ -0,0 +1,62 @@ +/* + * 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 React from 'react'; +import { + Header, + Page, + Content, + Progress, + ErrorPanel, +} from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import 'graphql-voyager/dist/voyager.css'; +import { graphQlVoyagerApiRef } from '../../lib/api'; +import useAsync from 'react-use/lib/useAsync'; +import { GraphQLVoyagerBrowser } from '../GraphQLVoyagerBrowser'; + +/** @public */ +export type GraphQLVoyagerPageProps = { + title?: string; +}; + +const VoyagerContent = () => { + const graphQLVoyagerApi = useApi(graphQlVoyagerApiRef); + + const { value, loading, error } = useAsync(() => + graphQLVoyagerApi.getEndpoints(), + ); + + if (loading) { + return ; + } else if (error) { + return ; + } + return ; +}; + +/** @public */ +export const GraphQLVoyagerPage = (props: GraphQLVoyagerPageProps) => { + const { title = 'Welcome to Voyager!' } = props; + + return ( + +
+ + + + + ); +}; diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/index.ts b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/index.ts new file mode 100644 index 0000000000..5ee042fd5f --- /dev/null +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerPage/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './GraphQLVoyagerPage'; diff --git a/plugins/graphql-voyager/src/components/index.ts b/plugins/graphql-voyager/src/components/index.ts new file mode 100644 index 0000000000..76c4229839 --- /dev/null +++ b/plugins/graphql-voyager/src/components/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export * from './GraphQLVoyagerPage'; +export * from './GraphQLVoyagerBrowser'; diff --git a/plugins/graphql-voyager/src/index.ts b/plugins/graphql-voyager/src/index.ts new file mode 100644 index 0000000000..9e314c2eef --- /dev/null +++ b/plugins/graphql-voyager/src/index.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ +export { graphqlVoyagerPlugin, GraphqlVoyagerPage } from './plugin'; +export { GraphQLVoyagerPage as Router } from './components'; +export type { GraphQLVoyagerPageProps } from './components'; +export * from './lib/api'; diff --git a/plugins/graphql-voyager/src/lib/api/GraphQLVoyagerEndpoints.ts b/plugins/graphql-voyager/src/lib/api/GraphQLVoyagerEndpoints.ts new file mode 100644 index 0000000000..4d08ffbce3 --- /dev/null +++ b/plugins/graphql-voyager/src/lib/api/GraphQLVoyagerEndpoints.ts @@ -0,0 +1,29 @@ +/* + * 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 { GraphQLVoyagerApi, GraphQLVoyagerEndpoint } from './types'; + +/** @public */ +export class GraphQLVoyagerEndpoints implements GraphQLVoyagerApi { + private constructor(private readonly endpoints: GraphQLVoyagerEndpoint[]) {} + + static from(endpoints: GraphQLVoyagerEndpoint[]) { + return new GraphQLVoyagerEndpoints(endpoints); + } + + async getEndpoints() { + return this.endpoints; + } +} diff --git a/plugins/graphql-voyager/src/lib/api/index.ts b/plugins/graphql-voyager/src/lib/api/index.ts new file mode 100644 index 0000000000..c52eedafb7 --- /dev/null +++ b/plugins/graphql-voyager/src/lib/api/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export * from './GraphQLVoyagerEndpoints'; +export * from './types'; diff --git a/plugins/graphql-voyager/src/lib/api/types.ts b/plugins/graphql-voyager/src/lib/api/types.ts new file mode 100644 index 0000000000..08e6f13923 --- /dev/null +++ b/plugins/graphql-voyager/src/lib/api/types.ts @@ -0,0 +1,141 @@ +/* + * 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 { createApiRef } from '@backstage/core-plugin-api'; +import { VoyagerDisplayOptions } from 'graphql-voyager/typings/components/Voyager'; +import { WorkerCallback } from 'graphql-voyager/typings/utils/types'; + +/** @public */ +export type GraphQLVoyagerEndpoint = { + id: string; + title: string; + introspection: (body: any) => Promise; + introspectionErrorMessage: string; + voyagerProps?: { + displayOptions?: VoyagerDisplayOptions; + hideDocs?: boolean; + hideSettings?: boolean; + workerURI?: string; + loadWorker?: WorkerCallback; + }; +}; + +/** @public */ +export type GraphQLVoyagerApi = { + getEndpoints(): Promise; +}; + +/** @public */ +export const graphQlVoyagerApiRef = createApiRef({ + id: 'plugin.graphqlvoyager.api', +}); + +/** @public */ +export const introspectionQuery: string = `query IntrospectionQuery { + __schema { + + queryType { name } + mutationType { name } + subscriptionType { name } + types { + ...FullType + } + directives { + name + description + + locations + args { + ...InputValue + } + } + } + } + + fragment FullType on __Type { + kind + name + description + + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + + fragment InputValue on __InputValue { + name + description + type { ...TypeRef } + defaultValue + + + } + + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + }`; diff --git a/plugins/graphql-voyager/src/plugin.test.ts b/plugins/graphql-voyager/src/plugin.test.ts new file mode 100644 index 0000000000..df7acc7143 --- /dev/null +++ b/plugins/graphql-voyager/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * 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 { graphqlVoyagerPlugin } from './plugin'; + +describe('graphql-voyager', () => { + it('should export plugin', () => { + expect(graphqlVoyagerPlugin).toBeDefined(); + }); +}); diff --git a/plugins/graphql-voyager/src/plugin.ts b/plugins/graphql-voyager/src/plugin.ts new file mode 100644 index 0000000000..bd33209a1d --- /dev/null +++ b/plugins/graphql-voyager/src/plugin.ts @@ -0,0 +1,38 @@ +/* + * 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 { + createPlugin, + createRoutableExtension, +} from '@backstage/core-plugin-api'; + +import { rootRouteRef } from './routes'; + +/** @public */ +export const graphqlVoyagerPlugin = createPlugin({ + id: 'graphql-voyager', + routes: { + root: rootRouteRef, + }, +}); + +/** @public */ +export const GraphqlVoyagerPage = graphqlVoyagerPlugin.provide( + createRoutableExtension({ + name: 'GraphqlVoyagerPage', + component: () => import('./components').then(m => m.GraphQLVoyagerPage), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/graphql-voyager/src/routes.ts b/plugins/graphql-voyager/src/routes.ts new file mode 100644 index 0000000000..12f06c1cb5 --- /dev/null +++ b/plugins/graphql-voyager/src/routes.ts @@ -0,0 +1,20 @@ +/* + * 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 { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'graphql-voyager', +}); diff --git a/plugins/graphql-voyager/src/setupTests.ts b/plugins/graphql-voyager/src/setupTests.ts new file mode 100644 index 0000000000..73dd8dce47 --- /dev/null +++ b/plugins/graphql-voyager/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * 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 '@testing-library/jest-dom'; +import 'cross-fetch/polyfill'; diff --git a/yarn.lock b/yarn.lock index 4e56cb9839..cdf50e0c78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3295,12 +3295,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.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.7, @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.2, @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.20.7 - resolution: "@babel/runtime@npm:7.20.7" +"@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.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.7, @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.2, @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.20.13 + resolution: "@babel/runtime@npm:7.20.13" dependencies: regenerator-runtime: ^0.13.11 - checksum: 4629ce5c46f06cca9cfb9b7fc00d48003335a809888e2b91ec2069a2dcfbfef738480cff32ba81e0b7c290f8918e5c22ddcf2b710001464ee84ba62c7e32a3a3 + checksum: 09b7a97a05c80540db6c9e4ddf8c5d2ebb06cae5caf3a87e33c33f27f8c4d49d9c67a2d72f1570e796045288fad569f98a26ceba0c4f5fad2af84b6ad855c4fb languageName: node linkType: hard @@ -6440,6 +6440,33 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-graphql-voyager@workspace:plugins/graphql-voyager": + version: 0.0.0-use.local + resolution: "@backstage/plugin-graphql-voyager@workspace:plugins/graphql-voyager" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/node": "*" + cross-fetch: ^3.1.5 + graphql-voyager: ^1.0.0-rc.31 + msw: ^0.49.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-home@npm:^0.4.30": version: 0.4.30 resolution: "@backstage/plugin-home@npm:0.4.30" @@ -9342,6 +9369,56 @@ __metadata: languageName: node linkType: hard +"@f/animate@npm:^1.0.1": + version: 1.0.1 + resolution: "@f/animate@npm:1.0.1" + dependencies: + "@f/elapsed-time": ^1.0.0 + "@f/raf": ^1.0.0 + "@f/tween": ^1.0.0 + checksum: 660b44d297b1a6e5e28c48438633e00ded40f8e51adb4bfb26fc809b60c8c056f567f2e61f4f842c8fd2cf8a85dffaa1c2502bd0963eb926135f2d66d9f997db + languageName: node + linkType: hard + +"@f/elapsed-time@npm:^1.0.0": + version: 1.0.0 + resolution: "@f/elapsed-time@npm:1.0.0" + dependencies: + "@f/timestamp": ^1.0.0 + checksum: 5934d24a667bae4e0089408aa362c0ee1503945adf73ca0ff0d09fed33d62d070f0323eb9a54f42c37bd0545330a0f63da13319f66cc89fef59b8917a3278b5f + languageName: node + linkType: hard + +"@f/map-obj@npm:^1.2.2": + version: 1.2.2 + resolution: "@f/map-obj@npm:1.2.2" + checksum: d67db6074e1daa7a3c0f8c2e54094bff48b54d11817fddc886631dd8a17586d0040e7116282a374cc1d3d643d05862d49a1062ea5b2d03b9069507c09ae888a4 + languageName: node + linkType: hard + +"@f/raf@npm:^1.0.0": + version: 1.0.3 + resolution: "@f/raf@npm:1.0.3" + checksum: 800344caf4c649c0bcdefd4febbf3f0eed96bb9b7e54b5bc6eebd7d781c9e6d98ba22fb39da41474080d97ac21916bd1e82051558b43dabcbbf410d2dd0899c1 + languageName: node + linkType: hard + +"@f/timestamp@npm:^1.0.0": + version: 1.0.0 + resolution: "@f/timestamp@npm:1.0.0" + checksum: 8c37acb40cf67952309a214be2ddfd5c4f6634a414efc47406e8d1c1624e74662f584f6b48f3382c742f256aea1537e730e74c6078e52be3a28d0624cc7306a0 + languageName: node + linkType: hard + +"@f/tween@npm:^1.0.0": + version: 1.0.1 + resolution: "@f/tween@npm:1.0.1" + dependencies: + "@f/map-obj": ^1.2.2 + checksum: e37155c43875becc9eca8425b8dc83e64a78fa327738b33fcb3946418369568aa77007ade39591991379187381da829702e5cb84729dd2a0bc3bb4b7c94e4f2b + languageName: node + linkType: hard + "@fmvilas/pseudo-yaml-ast@npm:^0.3.1": version: 0.3.1 resolution: "@fmvilas/pseudo-yaml-ast@npm:0.3.1" @@ -11402,6 +11479,44 @@ __metadata: languageName: node linkType: hard +"@material-ui/core@npm:^3.9.3": + version: 3.9.4 + resolution: "@material-ui/core@npm:3.9.4" + dependencies: + "@babel/runtime": ^7.2.0 + "@material-ui/system": ^3.0.0-alpha.0 + "@material-ui/utils": ^3.0.0-alpha.2 + "@types/jss": ^9.5.6 + "@types/react-transition-group": ^2.0.8 + brcast: ^3.0.1 + classnames: ^2.2.5 + csstype: ^2.5.2 + debounce: ^1.1.0 + deepmerge: ^3.0.0 + dom-helpers: ^3.2.1 + hoist-non-react-statics: ^3.2.1 + is-plain-object: ^2.0.4 + jss: ^9.8.7 + jss-camel-case: ^6.0.0 + jss-default-unit: ^8.0.2 + jss-global: ^3.0.0 + jss-nested: ^6.0.1 + jss-props-sort: ^6.0.0 + jss-vendor-prefixer: ^7.0.0 + normalize-scroll-left: ^0.1.2 + popper.js: ^1.14.1 + prop-types: ^15.6.0 + react-event-listener: ^0.6.2 + react-transition-group: ^2.2.1 + recompose: 0.28.0 - 0.30.0 + warning: ^4.0.1 + peerDependencies: + react: ^16.3.0 + react-dom: ^16.3.0 + checksum: c3923bfba4ef4449fbdcd37712ec0d11393ffa396c575a05b5f9530ca1e714028882d39402eb6918dad49f2eb1c53b261cfd0f2dfed494c2dfd96ee335336b44 + languageName: node + linkType: hard + "@material-ui/core@npm:^4.11.0, @material-ui/core@npm:^4.11.3, @material-ui/core@npm:^4.12.1, @material-ui/core@npm:^4.12.2, @material-ui/core@npm:^4.12.4": version: 4.12.4 resolution: "@material-ui/core@npm:4.12.4" @@ -11560,6 +11675,21 @@ __metadata: languageName: node linkType: hard +"@material-ui/system@npm:^3.0.0-alpha.0": + version: 3.0.0-alpha.2 + resolution: "@material-ui/system@npm:3.0.0-alpha.2" + dependencies: + "@babel/runtime": ^7.2.0 + deepmerge: ^3.0.0 + prop-types: ^15.6.0 + warning: ^4.0.1 + peerDependencies: + react: ^16.3.0 + react-dom: ^16.3.0 + checksum: 3aacb8b4afe2a820844b90905cfcd86ab934108cd719f11713ee46f8a4da30cb8c50e86219e1440b3c6dd333a09d4123cd1990d9c51862c1d56ec2b36e4d7ded + languageName: node + linkType: hard + "@material-ui/system@npm:^4.12.2": version: 4.12.2 resolution: "@material-ui/system@npm:4.12.2" @@ -11603,6 +11733,20 @@ __metadata: languageName: node linkType: hard +"@material-ui/utils@npm:^3.0.0-alpha.2": + version: 3.0.0-alpha.3 + resolution: "@material-ui/utils@npm:3.0.0-alpha.3" + dependencies: + "@babel/runtime": ^7.2.0 + prop-types: ^15.6.0 + react-is: ^16.6.3 + peerDependencies: + react: ^16.3.0 + react-dom: ^16.3.0 + checksum: 589a16245338c374b604a793d9f7a05bd932c9710f78261e46176b74a61d5d308b3e36dab688988ee5177d689c53d9e9da4649eca009ea11d8aac948db27af50 + languageName: node + linkType: hard + "@material-ui/utils@npm:^4.11.2, @material-ui/utils@npm:^4.11.3, @material-ui/utils@npm:^4.7.1": version: 4.11.3 resolution: "@material-ui/utils@npm:4.11.3" @@ -14790,6 +14934,16 @@ __metadata: languageName: node linkType: hard +"@types/jss@npm:^9.5.6": + version: 9.5.8 + resolution: "@types/jss@npm:9.5.8" + dependencies: + csstype: ^2.0.0 + indefinite-observable: ^1.0.1 + checksum: 6e51707529a15f2f5ff94555ecb555d29427fd10c4f3d2d29474934292e365c2dfaa4ad30b2ab46946201cbca7f6e8df56513a22fc6ceca10a979db8338935c5 + languageName: node + linkType: hard + "@types/jwt-decode@npm:^3.1.0": version: 3.1.0 resolution: "@types/jwt-decode@npm:3.1.0" @@ -15249,6 +15403,15 @@ __metadata: languageName: node linkType: hard +"@types/react-transition-group@npm:^2.0.8": + version: 2.9.2 + resolution: "@types/react-transition-group@npm:2.9.2" + dependencies: + "@types/react": "*" + checksum: 6f30fffc221339de90bd3e999f32328618cfaedfcaa501603f5ddc5bed1c2dbaa0d51347c3a25e5f8fd3041c671aabd2b7bfbcad611a7636adcd9da4e0666fa5 + languageName: node + linkType: hard + "@types/react-transition-group@npm:^4.2.0": version: 4.2.4 resolution: "@types/react-transition-group@npm:4.2.4" @@ -17896,6 +18059,13 @@ __metadata: languageName: node linkType: hard +"brcast@npm:^3.0.1": + version: 3.0.2 + resolution: "brcast@npm:3.0.2" + checksum: 7abae42088c6ffad9ff9e0fc756607a1764e299d737b3007fa49a73a38b3fda1e51362713f645db7991878ca388de94942011188450324c3debd08509315fa94 + languageName: node + linkType: hard + "breakword@npm:^1.0.5": version: 1.0.5 resolution: "breakword@npm:1.0.5" @@ -18478,6 +18648,13 @@ __metadata: languageName: node linkType: hard +"change-emitter@npm:^0.1.2": + version: 0.1.6 + resolution: "change-emitter@npm:0.1.6" + checksum: 0ed494ba9901ca56ea6f942668fd294465c334a9a0981dca96da5aea5e387c0023a630d7c658c1b532d203db54c928ddca2564e434b4a8b7f6d39155d09db255 + languageName: node + linkType: hard + "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" @@ -18734,6 +18911,17 @@ __metadata: languageName: node linkType: hard +"clipboard@npm:^2.0.4": + version: 2.0.11 + resolution: "clipboard@npm:2.0.11" + dependencies: + good-listener: ^1.2.2 + select: ^1.1.2 + tiny-emitter: ^2.0.0 + checksum: 413055a6038e43898e0e895216b58ed54fbf386f091cb00188875ef35b186cefbd258acdf4cb4b0ac87cbc00de936f41b45dde9fe1fd1a57f7babb28363b8748 + languageName: node + linkType: hard + "cliui@npm:^3.2.0": version: 3.2.0 resolution: "cliui@npm:3.2.0" @@ -19168,6 +19356,20 @@ __metadata: languageName: node linkType: hard +"commonmark@npm:^0.29.0": + version: 0.29.3 + resolution: "commonmark@npm:0.29.3" + dependencies: + entities: ~2.0 + mdurl: ~1.0.1 + minimist: ">=1.2.2" + string.prototype.repeat: ^0.2.0 + bin: + commonmark: bin/commonmark + checksum: 892b603aeffea6a04770ce24979fc4024d2d92ca6d5146353398faab15be980af6802f3d7b35357400b870e752a9f80b766fed5c09ca063a2951c8c26013876c + languageName: node + linkType: hard + "compare-versions@npm:4.1.3": version: 4.1.3 resolution: "compare-versions@npm:4.1.3" @@ -19493,6 +19695,13 @@ __metadata: languageName: node linkType: hard +"core-js@npm:^1.0.0": + version: 1.2.7 + resolution: "core-js@npm:1.2.7" + checksum: 0b76371bfa98708351cde580f9287e2360d2209920e738ae950ae74ad08639a2e063541020bf666c28778956fc356ed9fe56d962129c88a87a6a4a0612526c75 + languageName: node + linkType: hard + "core-js@npm:^2.4.0, core-js@npm:^2.5.0": version: 2.6.12 resolution: "core-js@npm:2.6.12" @@ -19857,6 +20066,15 @@ __metadata: languageName: node linkType: hard +"css-vendor@npm:^0.3.8": + version: 0.3.8 + resolution: "css-vendor@npm:0.3.8" + dependencies: + is-in-browser: ^1.0.2 + checksum: 0a2e0cd0d4adbfdb6236950e7f9697b8a9b294eb2ae7c95996a95d273d2a63316ce793cb4654ae048aa3c129327124d2a29aada9935a0c284f9cc341c2768c8a + languageName: node + linkType: hard + "css-vendor@npm:^2.0.8": version: 2.0.8 resolution: "css-vendor@npm:2.0.8" @@ -19998,10 +20216,10 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^2.5.2, csstype@npm:^2.6.7": - version: 2.6.17 - resolution: "csstype@npm:2.6.17" - checksum: 6eee5cf81a4b1b2f0e8707b4accd7504f7cceb4b5a496d58c6e4fcea1a70c1443a975e45d722c892d372ffe788fa278ddfe4d70c5f881375f34e48bb99c70ecc +"csstype@npm:^2.0.0, csstype@npm:^2.5.2, csstype@npm:^2.6.7": + version: 2.6.21 + resolution: "csstype@npm:2.6.21" + checksum: 2ce8bc832375146eccdf6115a1f8565a27015b74cce197c35103b4494955e9516b246140425ad24103864076aa3e1257ac9bab25a06c8d931dd87a6428c9dccf languageName: node linkType: hard @@ -20400,10 +20618,10 @@ __metadata: languageName: node linkType: hard -"debounce@npm:^1.2.0": - version: 1.2.0 - resolution: "debounce@npm:1.2.0" - checksum: e39cb593ae26344921f5a2681b40b703bdd22bc43b179f0e7515176c790997932b3a0ee6ea9864f384c6ac58cecc08158fb102c3632d5d88ab621f8230ee39ff +"debounce@npm:^1.1.0, debounce@npm:^1.2.0": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 682a89506d9e54fb109526f4da255c5546102fbb8e3ae75eef3b04effaf5d4853756aee97475cd4650641869794e44f410eeb20ace2b18ea592287ab2038519e languageName: node linkType: hard @@ -20573,6 +20791,13 @@ __metadata: languageName: node linkType: hard +"deepmerge@npm:^3.0.0": + version: 3.3.0 + resolution: "deepmerge@npm:3.3.0" + checksum: 4322195389e0170a0443c07b36add19b90249802c4b47b96265fdc5f5d8beddf491d5e50cbc5bfd65f85ccf76598173083863c202f5463b3b667aca8be75d5ac + languageName: node + linkType: hard + "deepmerge@npm:^4.2.2, deepmerge@npm:~4.2.2": version: 4.2.2 resolution: "deepmerge@npm:4.2.2" @@ -20652,6 +20877,13 @@ __metadata: languageName: node linkType: hard +"delegate@npm:^3.1.2": + version: 3.2.0 + resolution: "delegate@npm:3.2.0" + checksum: d943058fe05897228b158cbd1bab05164df28c8f54127873231d6b03b0a5acc1b3ee1f98ac70ccc9b79cd84aa47118a7de111fee2923753491583905069da27d + languageName: node + linkType: hard + "delegates@npm:^1.0.0": version: 1.0.0 resolution: "delegates@npm:1.0.0" @@ -20950,7 +21182,7 @@ __metadata: languageName: node linkType: hard -"dom-helpers@npm:^3.4.0": +"dom-helpers@npm:^3.2.1, dom-helpers@npm:^3.4.0": version: 3.4.0 resolution: "dom-helpers@npm:3.4.0" dependencies: @@ -21304,7 +21536,7 @@ __metadata: languageName: node linkType: hard -"encoding@npm:^0.1.12, encoding@npm:^0.1.13": +"encoding@npm:^0.1.11, encoding@npm:^0.1.12, encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" dependencies: @@ -21408,6 +21640,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:~2.0": + version: 2.0.3 + resolution: "entities@npm:2.0.3" + checksum: 5a7899fcc622e0d76afdeafe4c58a6b40ae3a8ee4772e5825a648c11a2ca324a9a02515386f512e466baac4aeb551f3d3b79eaece5cd98369b9f8601be336b1a + languageName: node + linkType: hard + "entities@npm:~2.1.0": version: 2.1.0 resolution: "entities@npm:2.1.0" @@ -23051,6 +23290,21 @@ __metadata: languageName: node linkType: hard +"fbjs@npm:^0.8.1": + version: 0.8.18 + resolution: "fbjs@npm:0.8.18" + dependencies: + core-js: ^1.0.0 + isomorphic-fetch: ^2.1.1 + loose-envify: ^1.0.0 + object-assign: ^4.1.0 + promise: ^7.1.1 + setimmediate: ^1.0.5 + ua-parser-js: ^0.7.30 + checksum: 668731b946a765908c9cbe51d5160f973abb78004b3d122587c3e930e3e1ddcc0ce2b17f2a8637dc9d733e149aa580f8d3035a35cc2d3bc78b78f1b19aab90e2 + languageName: node + linkType: hard + "fbjs@npm:^3.0.0": version: 3.0.0 resolution: "fbjs@npm:3.0.0" @@ -24079,6 +24333,15 @@ __metadata: languageName: node linkType: hard +"good-listener@npm:^1.2.2": + version: 1.2.2 + resolution: "good-listener@npm:1.2.2" + dependencies: + delegate: ^3.1.2 + checksum: f39fb82c4e41524f56104cfd2d7aef1a88e72f3f75139115fbdf98cc7d844e0c1b39218b2e83438c6188727bf904ed78c7f0f2feff67b32833bc3af7f0202b33 + languageName: node + linkType: hard + "google-auth-library@npm:^8.0.0, google-auth-library@npm:^8.0.1, google-auth-library@npm:^8.0.2": version: 8.7.0 resolution: "google-auth-library@npm:8.7.0" @@ -24291,6 +24554,27 @@ __metadata: languageName: node linkType: hard +"graphql-voyager@npm:^1.0.0-rc.31": + version: 1.0.0-rc.31 + resolution: "graphql-voyager@npm:1.0.0-rc.31" + dependencies: + "@f/animate": ^1.0.1 + "@material-ui/core": ^3.9.3 + classnames: ^2.2.6 + clipboard: ^2.0.4 + commonmark: ^0.29.0 + lodash: ^4.17.10 + prop-types: ^15.7.2 + svg-pan-zoom: ^3.6.0 + viz.js: 2.1.2 + peerDependencies: + graphql: ">=14.0.0" + react: ">=15.4.2" + react-dom: ">=15.4.2" + checksum: 80e826eeb42d286540447723ea35a463a3a155287914a45e24b69f31617d8ca74c0c43bdaa64123bf4ed046e68f7e31feca7661c06288551040f3e5b96c48fed + languageName: node + linkType: hard + "graphql-ws@npm:5.11.2, graphql-ws@npm:^5.4.1, graphql-ws@npm:^5.9.0": version: 5.11.2 resolution: "graphql-ws@npm:5.11.2" @@ -24625,7 +24909,14 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": +"hoist-non-react-statics@npm:^2.3.1": + version: 2.5.5 + resolution: "hoist-non-react-statics@npm:2.5.5" + checksum: ee2d05e5c7e1398ad84a15b0327f66bd78f38a8e0015e852f954b36434e32eb7e942d5357505020a3a1147f247b165bf1e69d72393e3accab67cafdafeb86230 + languageName: node + linkType: hard + +"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.2.1, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -25171,6 +25462,15 @@ __metadata: languageName: node linkType: hard +"indefinite-observable@npm:^1.0.1": + version: 1.0.2 + resolution: "indefinite-observable@npm:1.0.2" + dependencies: + symbol-observable: 1.2.0 + checksum: 69a337967f48fca18989f9d68ad98c7220ed9b499bf00330ff72669a9583cb7f8e82f801da10720f720edf1313f427c77ce793350bdc413c952cec8ce112fc12 + languageName: node + linkType: hard + "indefinite-observable@npm:^2.0.1": version: 2.0.1 resolution: "indefinite-observable@npm:2.0.1" @@ -25937,6 +26237,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^1.0.1": + version: 1.1.0 + resolution: "is-stream@npm:1.1.0" + checksum: 063c6bec9d5647aa6d42108d4c59723d2bd4ae42135a2d4db6eadbd49b7ea05b750fd69d279e5c7c45cf9da753ad2c00d8978be354d65aa9f6bb434969c6a2ae + languageName: node + linkType: hard + "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" @@ -26139,6 +26446,16 @@ __metadata: languageName: node linkType: hard +"isomorphic-fetch@npm:^2.1.1": + version: 2.2.1 + resolution: "isomorphic-fetch@npm:2.2.1" + dependencies: + node-fetch: ^1.0.1 + whatwg-fetch: ">=0.10.0" + checksum: bb5daa7c3785d6742f4379a81e55b549a469503f7c9bf9411b48592e86632cf5e8fe8ea878dba185c0f33eb7c510c23abdeb55aebfdf5d3c70f031ced68c5424 + languageName: node + linkType: hard + "isomorphic-fetch@npm:^3.0.0": version: 3.0.0 resolution: "isomorphic-fetch@npm:3.0.0" @@ -27497,6 +27814,46 @@ __metadata: languageName: node linkType: hard +"jss-camel-case@npm:^6.0.0": + version: 6.1.0 + resolution: "jss-camel-case@npm:6.1.0" + dependencies: + hyphenate-style-name: ^1.0.2 + peerDependencies: + jss: ^9.7.0 + checksum: f20ad892cddc30241b5127d648233b513ce57b2a6ed2f710cd995510f8d06e1418cd8f6e8e50dc6bd60b2e8a35159bfdeb40143938e0f2cdc19fd39279953789 + languageName: node + linkType: hard + +"jss-default-unit@npm:^8.0.2": + version: 8.0.2 + resolution: "jss-default-unit@npm:8.0.2" + peerDependencies: + jss: ^9.4.0 + checksum: 5277c5ccc3d56f5c137d6d65f0fc36d15eb22ef08b5949e887ee75e9f4f25197e25f2a99706b70a2828cee010fd8ed7484fb1bb2086fe327f2b24b1bdcc22abb + languageName: node + linkType: hard + +"jss-global@npm:^3.0.0": + version: 3.0.0 + resolution: "jss-global@npm:3.0.0" + peerDependencies: + jss: ^9.0.0 + checksum: e3fa80d8251ba5f183d9b0b4416d64e8f5d285cfdb595cc600daf1a1366b67bca573939bb71d98b6596bf4d6f2c95711cf53a358af3d63cd7945dbb434c6547b + languageName: node + linkType: hard + +"jss-nested@npm:^6.0.1": + version: 6.0.1 + resolution: "jss-nested@npm:6.0.1" + dependencies: + warning: ^3.0.0 + peerDependencies: + jss: ^9.0.0 + checksum: 437bdacc559be0b4b5bc1faa2bc77b5c6cf14733fefbf73a34bb7335786b9f08e4e79b3d73cf83b386959adcd8fa9d725877912e96d9a0921ed38baa1a69b8d9 + languageName: node + linkType: hard + "jss-plugin-camel-case@npm:^10.5.1": version: 10.6.0 resolution: "jss-plugin-camel-case@npm:10.6.0" @@ -27571,6 +27928,26 @@ __metadata: languageName: node linkType: hard +"jss-props-sort@npm:^6.0.0": + version: 6.0.0 + resolution: "jss-props-sort@npm:6.0.0" + peerDependencies: + jss: ^9.0.0 + checksum: 82a04f625a2f2b3a71b2fcb00b1ed0478137c83dc47c323d24c7ea88d08c9ea295b061f99cf264db133fef3435366d6da594724f7713e0415dc50b4eff2aeb53 + languageName: node + linkType: hard + +"jss-vendor-prefixer@npm:^7.0.0": + version: 7.0.0 + resolution: "jss-vendor-prefixer@npm:7.0.0" + dependencies: + css-vendor: ^0.3.8 + peerDependencies: + jss: ^9.0.0 + checksum: 8ec3608711833e79da7ccfffd8177e752f16093589fa28d3a24ec19e6588fbc6a07cc5cacf59ef4c111ab1d0fb72e07b88cb3444eb8c0c6ed4cc8107da984633 + languageName: node + linkType: hard + "jss@npm:10.6.0": version: 10.6.0 resolution: "jss@npm:10.6.0" @@ -27596,6 +27973,17 @@ __metadata: languageName: node linkType: hard +"jss@npm:^9.8.7": + version: 9.8.7 + resolution: "jss@npm:9.8.7" + dependencies: + is-in-browser: ^1.1.3 + symbol-observable: ^1.1.0 + warning: ^3.0.0 + checksum: ebb264cc893fb8c17a0277875947f8f72e01f5be991bf7f61a39abb861e1276e75ee402fdd2be9ce827af839a1a08bd81ad86a4e108d57fd7d7ebb2361837a53 + languageName: node + linkType: hard + "jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": version: 3.3.3 resolution: "jsx-ast-utils@npm:3.3.3" @@ -28899,7 +29287,7 @@ __metadata: languageName: node linkType: hard -"mdurl@npm:^1.0.0, mdurl@npm:^1.0.1": +"mdurl@npm:^1.0.0, mdurl@npm:^1.0.1, mdurl@npm:~1.0.1": version: 1.0.1 resolution: "mdurl@npm:1.0.1" checksum: 71731ecba943926bfbf9f9b51e28b5945f9411c4eda80894221b47cc105afa43ba2da820732b436f0798fd3edbbffcd1fc1415843c41a87fea08a41cc1e3d02b @@ -29560,7 +29948,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7": +"minimist@npm:>=1.2.2, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7": version: 1.2.7 resolution: "minimist@npm:1.2.7" checksum: 7346574a1038ca23c32e02252f603801f09384dd1d78b69a943a4e8c2c28730b80e96193882d3d3b22a063445f460e48316b29b8a25addca2d7e5e8f75478bec @@ -30104,6 +30492,16 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^1.0.1": + version: 1.7.3 + resolution: "node-fetch@npm:1.7.3" + dependencies: + encoding: ^0.1.11 + is-stream: ^1.0.1 + checksum: 3bb0528c05d541316ebe52770d71ee25a6dce334df4231fd55df41a644143e07f068637488c18a5b0c43f05041dbd3346752f9e19b50df50569a802484544d5b + languageName: node + linkType: hard + "node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.5, node-fetch@npm:^2.6.7": version: 2.6.9 resolution: "node-fetch@npm:2.6.9" @@ -30311,6 +30709,13 @@ __metadata: languageName: node linkType: hard +"normalize-scroll-left@npm:^0.1.2": + version: 0.1.2 + resolution: "normalize-scroll-left@npm:0.1.2" + checksum: 817d5a659ba6f14f458cd03a5a0f98ec2a9d7e6c63c160f2db164827b87bb77c0237752890a18d11054fe628907493c5f4d8914907585ec9fbba3de26d2a6815 + languageName: node + linkType: hard + "normalize-url@npm:^6.0.1": version: 6.1.0 resolution: "normalize-url@npm:6.1.0" @@ -31968,6 +32373,13 @@ __metadata: languageName: node linkType: hard +"popper.js@npm:^1.14.1": + version: 1.16.1 + resolution: "popper.js@npm:1.16.1" + checksum: c56ae5001ec50a77ee297a8061a0221d99d25c7348d2e6bcd3e45a0d0f32a1fd81bca29d46cb0d4bdf13efb77685bd6a0ce93f9eb3c608311a461f945fffedbe + languageName: node + linkType: hard + "postcss-calc@npm:^8.0.0": version: 8.0.0 resolution: "postcss-calc@npm:8.0.0" @@ -32652,7 +33064,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": +"prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -33230,6 +33642,19 @@ __metadata: languageName: node linkType: hard +"react-event-listener@npm:^0.6.2": + version: 0.6.6 + resolution: "react-event-listener@npm:0.6.6" + dependencies: + "@babel/runtime": ^7.2.0 + prop-types: ^15.6.0 + warning: ^4.0.1 + peerDependencies: + react: ^16.3.0 + checksum: 0287e0ae8cbf0a4c03889ffc2b745f5494b3edea0f4667357d709f5646dd78c7289ce305b6f473ec6ac5789f8a937c86b7e543d0249f0bf787bccdb1eab7ecd0 + languageName: node + linkType: hard + "react-fast-compare@npm:^3.1.1": version: 3.2.0 resolution: "react-fast-compare@npm:3.2.0" @@ -33310,7 +33735,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.10.2, react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0, react-is@npm:^16.8.0, react-is@npm:^16.8.6, react-is@npm:^16.9.0": +"react-is@npm:^16.10.2, react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.3, react-is@npm:^16.7.0, react-is@npm:^16.8.0, react-is@npm:^16.8.6, react-is@npm:^16.9.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -33331,7 +33756,7 @@ __metadata: languageName: node linkType: hard -"react-lifecycles-compat@npm:^3.0.4": +"react-lifecycles-compat@npm:^3.0.2, react-lifecycles-compat@npm:^3.0.4": version: 3.0.4 resolution: "react-lifecycles-compat@npm:3.0.4" checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f @@ -33532,7 +33957,7 @@ __metadata: languageName: node linkType: hard -"react-transition-group@npm:2.9.0": +"react-transition-group@npm:2.9.0, react-transition-group@npm:^2.2.1": version: 2.9.0 resolution: "react-transition-group@npm:2.9.0" dependencies: @@ -33844,6 +34269,22 @@ __metadata: languageName: node linkType: hard +"recompose@npm:0.28.0 - 0.30.0": + version: 0.30.0 + resolution: "recompose@npm:0.30.0" + dependencies: + "@babel/runtime": ^7.0.0 + change-emitter: ^0.1.2 + fbjs: ^0.8.1 + hoist-non-react-statics: ^2.3.1 + react-lifecycles-compat: ^3.0.2 + symbol-observable: ^1.0.4 + peerDependencies: + react: ^0.14.0 || ^15.0.0 || ^16.0.0 + checksum: 18e58252336d0628b22db1e38407d32e836648e6d5c9453ba37c9f8030138b3429ee3952b053a13b60311f8b60893b207a761466bb293083542db0cf317b7a41 + languageName: node + linkType: hard + "recursive-readdir@npm:^2.2.2": version: 2.2.3 resolution: "recursive-readdir@npm:2.2.3" @@ -34923,6 +35364,13 @@ __metadata: languageName: node linkType: hard +"select@npm:^1.1.2": + version: 1.1.2 + resolution: "select@npm:1.1.2" + checksum: 4346151e94f226ea6131e44e68e6d837f3fdee64831b756dd657cc0b02f4cb5107f867cb34a1d1216ab7737d0bf0645d44546afb030bbd8d64e891f5e4c4814e + languageName: node + linkType: hard + "selfsigned@npm:^2.0.0, selfsigned@npm:^2.1.1": version: 2.1.1 resolution: "selfsigned@npm:2.1.1" @@ -36114,6 +36562,13 @@ __metadata: languageName: node linkType: hard +"string.prototype.repeat@npm:^0.2.0": + version: 0.2.0 + resolution: "string.prototype.repeat@npm:0.2.0" + checksum: 5127ce1b5bce45258905877048ac28bae71be18f1c3421011bd3979cfbcacf9c16f6b7f42daa3b999c9d90f5da39bd7136982c8e64439f02666dd6c0778ed262 + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimend@npm:1.0.5" @@ -36461,6 +36916,13 @@ __metadata: languageName: node linkType: hard +"svg-pan-zoom@npm:^3.6.0": + version: 3.6.1 + resolution: "svg-pan-zoom@npm:3.6.1" + checksum: 500b99378d321315e1668067ef6a73af3f61f9adfab75a575b21d2d216cb446def61d60ad12265203463cca9bef56b090f00e48118fa9b7f0ffa1c691e4c1621 + languageName: node + linkType: hard + "svg-parser@npm:^2.0.4": version: 2.0.4 resolution: "svg-parser@npm:2.0.4" @@ -36581,7 +37043,7 @@ __metadata: languageName: node linkType: hard -"symbol-observable@npm:1.2.0, symbol-observable@npm:^1.0.4": +"symbol-observable@npm:1.2.0, symbol-observable@npm:^1.0.4, symbol-observable@npm:^1.1.0": version: 1.2.0 resolution: "symbol-observable@npm:1.2.0" checksum: 48ffbc22e3d75f9853b3ff2ae94a44d84f386415110aea5effc24d84c502e03a4a6b7a8f75ebaf7b585780bda34eb5d6da3121f826a6f93398429d30032971b6 @@ -36934,6 +37396,13 @@ __metadata: languageName: node linkType: hard +"tiny-emitter@npm:^2.0.0": + version: 2.1.0 + resolution: "tiny-emitter@npm:2.1.0" + checksum: fbcfb5145751a0e3b109507a828eb6d6d4501352ab7bb33eccef46e22e9d9ad3953158870a6966a59e57ab7c3f9cfac7cab8521db4de6a5e757012f4677df2dd + languageName: node + linkType: hard + "tiny-invariant@npm:^1.0.6": version: 1.1.0 resolution: "tiny-invariant@npm:1.1.0" @@ -37528,7 +37997,7 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.18": +"ua-parser-js@npm:^0.7.18, ua-parser-js@npm:^0.7.30": version: 0.7.33 resolution: "ua-parser-js@npm:0.7.33" checksum: 1510e9ec26fcaf0d8c6ae8f1078a8230e8816f083e1b5f453ea19d06b8ef2b8a596601c92148fd41899e8b3e5f83fa69c42332bd5729b931a721040339831696 @@ -38272,6 +38741,13 @@ __metadata: languageName: node linkType: hard +"viz.js@npm:2.1.2": + version: 2.1.2 + resolution: "viz.js@npm:2.1.2" + checksum: 299e5a8519a472e0e98197c5f39c0ca6f3f6c4642b6ae007ed888fea998d82455c7ae0118d09cb888bfd2c46ebe3b03d7ce321a4eef1c822a5f5719d3a6ef3bb + languageName: node + linkType: hard + "vm-browserify@npm:^1.0.1": version: 1.1.2 resolution: "vm-browserify@npm:1.1.2" @@ -38370,6 +38846,24 @@ __metadata: languageName: node linkType: hard +"warning@npm:^3.0.0": + version: 3.0.0 + resolution: "warning@npm:3.0.0" + dependencies: + loose-envify: ^1.0.0 + checksum: c9f99a12803aab81b29858e7dc3415bf98b41baee3a4c3acdeb680d98c47b6e17490f1087dccc54432deed5711a5ce0ebcda2b27e9b5eb054c32ae50acb4419c + languageName: node + linkType: hard + +"warning@npm:^4.0.1": + version: 4.0.3 + resolution: "warning@npm:4.0.3" + dependencies: + loose-envify: ^1.0.0 + checksum: 4f2cb6a9575e4faf71ddad9ad1ae7a00d0a75d24521c193fa464f30e6b04027bd97aa5d9546b0e13d3a150ab402eda216d59c1d0f2d6ca60124d96cd40dfa35c + languageName: node + linkType: hard + "watchpack@npm:^2.0.0-beta.10, watchpack@npm:^2.4.0": version: 2.4.0 resolution: "watchpack@npm:2.4.0" @@ -38622,7 +39116,7 @@ __metadata: languageName: node linkType: hard -"whatwg-fetch@npm:^3.0.0, whatwg-fetch@npm:^3.4.1": +"whatwg-fetch@npm:>=0.10.0, whatwg-fetch@npm:^3.0.0, whatwg-fetch@npm:^3.4.1": version: 3.6.2 resolution: "whatwg-fetch@npm:3.6.2" checksum: ee976b7249e7791edb0d0a62cd806b29006ad7ec3a3d89145921ad8c00a3a67e4be8f3fb3ec6bc7b58498724fd568d11aeeeea1f7827e7e1e5eae6c8a275afed