diff --git a/.changeset/honest-ants-type.md b/.changeset/honest-ants-type.md new file mode 100644 index 0000000000..9d8a6e4e65 --- /dev/null +++ b/.changeset/honest-ants-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-apollo-explorer': minor +--- + +Apollo Explorer plugin now available! Installation instructions can be found in the plugin README diff --git a/packages/app/package.json b/packages/app/package.json index 08833ca1a3..b936136776 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -49,18 +49,18 @@ "@backstage/plugin-rollbar": "^0.4.7-next.3", "@backstage/plugin-scaffolder": "^1.4.0-next.3", "@backstage/plugin-search": "^0.9.1-next.3", - "@backstage/plugin-search-react": "^0.2.2-next.3", "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-search-react": "^0.2.2-next.3", "@backstage/plugin-sentry": "^0.4.0-next.3", "@backstage/plugin-shortcuts": "^0.2.8-next.3", "@backstage/plugin-stack-overflow": "^0.1.3-next.3", + "@backstage/plugin-tech-insights": "^0.2.3-next.3", "@backstage/plugin-tech-radar": "^0.5.14-next.3", "@backstage/plugin-techdocs": "^1.2.1-next.3", - "@backstage/plugin-techdocs-react": "^1.0.2-next.2", "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.2-next.3", + "@backstage/plugin-techdocs-react": "^1.0.2-next.2", "@backstage/plugin-todo": "^0.2.9-next.3", "@backstage/plugin-user-settings": "^0.4.6-next.3", - "@backstage/plugin-tech-insights": "^0.2.3-next.3", "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/apollo-explorer/.eslintrc.js b/plugins/apollo-explorer/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/apollo-explorer/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/apollo-explorer/README.md b/plugins/apollo-explorer/README.md new file mode 100644 index 0000000000..98f3116966 --- /dev/null +++ b/plugins/apollo-explorer/README.md @@ -0,0 +1,66 @@ +# apollo-explorer + +Welcome to the Apollo Explorer plugin! + +This plugin allows users to directly embed an [Apollo](https://www.apollographql.com) graph explorer directly into +Backstage! + +## Getting started + +### Getting an Apollo Graph Reference + +First things first, you will need an Apollo account, and a graph imported into your account. This is beyond the scope of +this plugin, so if you are totally new to Apollo, please reference their official +documentation [here](https://www.apollographql.com/docs). + +Once you have a graph set up in Apollo, we need to grab the graph reference. First, go to your Apollo graphs home page and choose the graph you wish to embed. + +![Apollo Graph List](./docs/img/apollo-graph-list.png) + +Once you are in your graph explorer, click the dropdown next to the share icon and select `Share as Embedded` + +![Share as Embedded](./docs/img/share-as-embedded.png) + +This modal contains a number of useful properties, all of which can be passed to the plugin via the component properties, but the only mandatory input we need from here is the `graphRef`. + +![Graph Ref](./docs/img/graph-ref.png) + +Hold on to this snippet for a second while we set up the plugin ✨ + +### Installing the Backstage Plugin + +First, add the plugin to your Backstage app + +```shell +yarn --cwd packages/app add @backstage/plugin-apollo-explorer +``` + +Then, in `packages/app/src/App.tsx` add the plugin as a `Route` + +```typescript + + } +/> +``` + +Then, in `packages/app/src/components/Root/Root.tsx` add a sidebar item so users can find your beautiful plugin! + +```typescript + +``` + +That's it! You should now see an `Apollo Explorer` item in your sidebar, and if you click it, you should see your graph(s) load and direct you to authenticate via Apollo! + +![Needs Auth](./docs/img/needs-auth.png) + +Once you authenticate, your graph is ready to use 🚀 + +![Logged In](./docs/img/logged-in.png) diff --git a/plugins/apollo-explorer/api-report.md b/plugins/apollo-explorer/api-report.md new file mode 100644 index 0000000000..593f8f3004 --- /dev/null +++ b/plugins/apollo-explorer/api-report.md @@ -0,0 +1,48 @@ +## API Report File for "@backstage/plugin-apollo-explorer" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { JSONObject } from '@apollo/explorer/src/helpers/types'; +import { RouteRef } from '@backstage/core-plugin-api'; + +// @public +export const ApolloExplorerPage: ({ + title, + subtitle, + endpoints, +}: { + title?: string | undefined; + subtitle?: string | undefined; + endpoints: { + title: string; + graphRef: string; + persistExplorerState?: boolean | undefined; + initialState?: + | { + document?: string | undefined; + variables?: JSONObject | undefined; + headers?: Record | undefined; + displayOptions: { + docsPanelState?: 'closed' | 'open' | undefined; + showHeadersAndEnvVars?: boolean | undefined; + theme?: 'dark' | 'light' | undefined; + }; + } + | undefined; + }[]; +}) => JSX.Element; + +// @public +export const apolloExplorerPlugin: BackstagePlugin< + { + root: RouteRef; + }, + {} +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/apollo-explorer/dev/index.tsx b/plugins/apollo-explorer/dev/index.tsx new file mode 100644 index 0000000000..df61267811 --- /dev/null +++ b/plugins/apollo-explorer/dev/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { createDevApp } from '@backstage/dev-utils'; +import { apolloExplorerPlugin, ApolloExplorerPage } from '../src/plugin'; + +createDevApp() + .registerPlugin(apolloExplorerPlugin) + .addPage({ + element: , + title: 'Root Page', + path: '/apollo-explorer', + }) + .render(); diff --git a/plugins/apollo-explorer/docs/img/apollo-graph-list.png b/plugins/apollo-explorer/docs/img/apollo-graph-list.png new file mode 100644 index 0000000000..53a1c517aa Binary files /dev/null and b/plugins/apollo-explorer/docs/img/apollo-graph-list.png differ diff --git a/plugins/apollo-explorer/docs/img/graph-ref.png b/plugins/apollo-explorer/docs/img/graph-ref.png new file mode 100644 index 0000000000..062ebe50b7 Binary files /dev/null and b/plugins/apollo-explorer/docs/img/graph-ref.png differ diff --git a/plugins/apollo-explorer/docs/img/logged-in.png b/plugins/apollo-explorer/docs/img/logged-in.png new file mode 100644 index 0000000000..5c5c81347d Binary files /dev/null and b/plugins/apollo-explorer/docs/img/logged-in.png differ diff --git a/plugins/apollo-explorer/docs/img/needs-auth.png b/plugins/apollo-explorer/docs/img/needs-auth.png new file mode 100644 index 0000000000..03c6a9c5fc Binary files /dev/null and b/plugins/apollo-explorer/docs/img/needs-auth.png differ diff --git a/plugins/apollo-explorer/docs/img/share-as-embedded.png b/plugins/apollo-explorer/docs/img/share-as-embedded.png new file mode 100644 index 0000000000..672ed5d8ef Binary files /dev/null and b/plugins/apollo-explorer/docs/img/share-as-embedded.png differ diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json new file mode 100644 index 0000000000..9d8f2037ba --- /dev/null +++ b/plugins/apollo-explorer/package.json @@ -0,0 +1,54 @@ +{ + "name": "@backstage/plugin-apollo-explorer", + "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": "^0.10.0-next.3", + "@backstage/core-plugin-api": "^1.0.4-next.0", + "@backstage/theme": "^0.2.16-next.1", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.57", + "react-use": "^17.2.4", + "@apollo/explorer": "^1.1.1", + "use-deep-compare-effect": "^1.8.1" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.18.0-next.3", + "@backstage/core-app-api": "^1.0.4-next.1", + "@backstage/dev-utils": "^1.0.4-next.3", + "@backstage/test-utils": "^1.1.2-next.2", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/jest": "*", + "@types/node": "*", + "msw": "^0.43.0", + "cross-fetch": "^3.1.5" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/ApolloExplorerBrowser.tsx b/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/ApolloExplorerBrowser.tsx new file mode 100644 index 0000000000..bce3ce00bb --- /dev/null +++ b/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/ApolloExplorerBrowser.tsx @@ -0,0 +1,85 @@ +/* + * 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, { useState } from 'react'; +import { Divider, makeStyles, Tab, Tabs } from '@material-ui/core'; +import { BackstageTheme } from '@backstage/theme'; +import { JSONObject } from '@apollo/explorer/src/helpers/types'; +import { ApolloExplorer } from '@apollo/explorer/react'; +import { Content } from '@backstage/core-components'; + +const useStyles = makeStyles(theme => ({ + tabs: { + background: theme.palette.background.paper, + }, + root: { + height: '100%', + }, + content: { + height: '100%', + }, + explorer: { + height: '95%', + }, +})); + +export type ApolloEndpointProps = { + title: string; + graphRef: string; + persistExplorerState?: boolean; + initialState?: { + document?: string; + variables?: JSONObject; + headers?: Record; + displayOptions: { + docsPanelState?: 'open' | 'closed'; + showHeadersAndEnvVars?: boolean; + theme?: 'dark' | 'light'; + }; + }; +}; + +type Props = { + endpoints: ApolloEndpointProps[]; +}; + +export const ApolloExplorerBrowser = ({ endpoints }: Props) => { + const classes = useStyles(); + const [tabIndex, setTabIndex] = useState(0); + + return ( +
+ setTabIndex(value)} + indicatorColor="primary" + > + {endpoints.map(({ title }, index) => ( + + ))} + + + + + +
+ ); +}; diff --git a/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/index.ts b/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/index.ts new file mode 100644 index 0000000000..d8bc44bfa7 --- /dev/null +++ b/plugins/apollo-explorer/src/components/ApolloExplorerBrowser/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { ApolloExplorerBrowser } from './ApolloExplorerBrowser'; diff --git a/plugins/apollo-explorer/src/components/ApolloExplorerPage/ApolloExplorerPage.tsx b/plugins/apollo-explorer/src/components/ApolloExplorerPage/ApolloExplorerPage.tsx new file mode 100644 index 0000000000..c2c02fc646 --- /dev/null +++ b/plugins/apollo-explorer/src/components/ApolloExplorerPage/ApolloExplorerPage.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Content, Header, Page } from '@backstage/core-components'; +import { ApolloExplorerBrowser } from '../ApolloExplorerBrowser'; +import { JSONObject } from '@apollo/explorer/src/helpers/types'; + +type EndpointProps = { + title: string; + graphRef: string; + persistExplorerState?: boolean; + initialState?: { + document?: string; + variables?: JSONObject; + headers?: Record; + displayOptions: { + docsPanelState?: 'open' | 'closed'; + showHeadersAndEnvVars?: boolean; + theme?: 'dark' | 'light'; + }; + }; +}; + +type Props = { + title?: string | undefined; + subtitle?: string | undefined; + endpoints: EndpointProps[]; +}; + +export const ApolloExplorerPage = ({ title, subtitle, endpoints }: Props) => { + return ( + +
+ + + + + ); +}; diff --git a/plugins/apollo-explorer/src/components/ApolloExplorerPage/index.ts b/plugins/apollo-explorer/src/components/ApolloExplorerPage/index.ts new file mode 100644 index 0000000000..8f62872fe6 --- /dev/null +++ b/plugins/apollo-explorer/src/components/ApolloExplorerPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { ApolloExplorerPage } from './ApolloExplorerPage'; diff --git a/plugins/apollo-explorer/src/index.ts b/plugins/apollo-explorer/src/index.ts new file mode 100644 index 0000000000..6d07535fc3 --- /dev/null +++ b/plugins/apollo-explorer/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { apolloExplorerPlugin, ApolloExplorerPage } from './plugin'; diff --git a/plugins/apollo-explorer/src/plugin.test.ts b/plugins/apollo-explorer/src/plugin.test.ts new file mode 100644 index 0000000000..0b5e41fe6e --- /dev/null +++ b/plugins/apollo-explorer/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { apolloExplorerPlugin } from './plugin'; + +describe('apollo-explorer', () => { + it('should export plugin', () => { + expect(apolloExplorerPlugin).toBeDefined(); + }); +}); diff --git a/plugins/apollo-explorer/src/plugin.ts b/plugins/apollo-explorer/src/plugin.ts new file mode 100644 index 0000000000..6f7321689b --- /dev/null +++ b/plugins/apollo-explorer/src/plugin.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + createPlugin, + createRoutableExtension, +} from '@backstage/core-plugin-api'; + +import { rootRouteRef } from './routes'; + +/** + * Plugin that allows Apollo Explorer instances to be directly embedded into Backstage + * @public + */ +export const apolloExplorerPlugin = createPlugin({ + id: 'apollo-explorer', + routes: { + root: rootRouteRef, + }, +}); + +/** + * Main component that wraps the embedded graph(s) + * @public + */ +export const ApolloExplorerPage = apolloExplorerPlugin.provide( + createRoutableExtension({ + name: 'ApolloExplorerPage', + component: () => + import('./components/ApolloExplorerPage').then(m => m.ApolloExplorerPage), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/apollo-explorer/src/routes.ts b/plugins/apollo-explorer/src/routes.ts new file mode 100644 index 0000000000..c8e6a3eb9a --- /dev/null +++ b/plugins/apollo-explorer/src/routes.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'apollo-explorer', +}); diff --git a/plugins/apollo-explorer/src/setupTests.ts b/plugins/apollo-explorer/src/setupTests.ts new file mode 100644 index 0000000000..9bb3e72355 --- /dev/null +++ b/plugins/apollo-explorer/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; +import 'cross-fetch/polyfill';