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.
+
+
+
+Once you are in your graph explorer, click the dropdown next to the share icon and select `Share as Embedded`
+
+
+
+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`.
+
+
+
+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!
+
+
+
+Once you authenticate, your graph is ready to use 🚀
+
+
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';