diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml
index 7d30814c07..d7a862806a 100644
--- a/.github/workflows/frontend.yml
+++ b/.github/workflows/frontend.yml
@@ -45,6 +45,9 @@ jobs:
run: git diff --quiet origin/master HEAD -- yarn.lock
continue-on-error: true
+ - name: verify doc links
+ run: node docs/verify-links.js
+
- name: yarn install
run: yarn install --frozen-lockfile
diff --git a/README.md b/README.md
index d401650a66..56932a1741 100644
--- a/README.md
+++ b/README.md
@@ -10,33 +10,20 @@
## What is Backstage?
-[Backstage](https://backstage.io/) is an open platform for building developer portals. It’s based on the developer portal we’ve been using internally at Spotify for over four years. Backstage can be as simple as a services catalog or as powerful as the UX layer for your entire tech infrastructure.
+[Backstage](https://backstage.io/) is an open platform for building developer portals. Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure. So your product teams can ship high-quality code quickly — without compromising autonomy.
-For more information go to [backstage.io](https://backstage.io) or join our [Discord chatroom](https://discord.gg/EBHEGzX).
-
-### Features
-
-- Create and manage all of your organization’s software and microservices in one place.
-- Services catalog keeps track of all software and its ownership.
-- Visualizations provide information about your backend services and tooling, and help you monitor them.
-- A unified method for managing microservices offers both visibility and control.
-- Preset templates allow engineers to quickly create microservices in a standardized way ([coming soon](https://github.com/spotify/backstage/milestone/11)).
-- Centralized, full-featured technical documentation with integrated tooling that makes it easy for developers to set up, publish, and maintain alongside their code ([coming soon](https://github.com/spotify/backstage/milestone/15)).
-
-### Benefits
-
-- For _engineering managers_, it allows you to maintain standards and best practices across the organization, and can help you manage your whole tech ecosystem, from migrations to test certification.
-- For _end users_ (developers), it makes it fast and simple to build software components in a standardized way, and it provides a central place to manage all projects and documentation.
-- For _platform engineers_, it enables extensibility and scalability by letting you easily integrate new tools and services (via plugins), as well as extending the functionality of existing ones.
-- For _everyone_, it’s a single, consistent experience that ties all your infrastructure tooling, resources, standards, owners, contributors, and administrators together in one place.
-
-## Backstage Service Catalog (alpha)
-
-The Backstage Service Catalog — actually, a software catalog, since it includes more than just services — is a centralized system that keeps track of ownership and metadata for all the software in your ecosystem (services, websites, libraries, data pipelines, etc). The catalog is built around the concept of [metadata yaml files](https://github.com/spotify/backstage/blob/master/docs/architecture-decisions/adr002-default-catalog-file-format.md#format) stored together with the code, which are then harvested and visualized in Backstage.
+Backstage unifies all your infrastructure tooling, services, and documentation to create a streamlined development environment from end to end.

-We have also found that the service catalog is a great way to organise the infrastructure tools you use to manage the software as well. This is how Backstage creates one developer portal for all your tools. Rather than asking teams to jump between different infrastructure UI’s (and incurring additional cognitive overhead each time they make a context switch), most of these tools can be organised around the entities in the catalog.
+Out of the box, Backstage includes:
+
+- [Backstage Service Catalog](https://github.com/spotify/backstage/blob/master/docs/features/software-catalog/index.md) for managing all your software (microservices, libraries, data pipelines, websites, ML models, etc.)
+- [Backstage Software Templates](https://github.com/spotify/backstage/blob/master/docs/features/software-templates/index.md) for quickly spinning up new projects and standardizing your tooling with your organization’s best practices
+- [Backstage TechDocs](https://github.com/spotify/backstage/tree/master/docs/features/techdocs) for making it easy to create, maintain, find, and use technical documentation, using a "docs like code" approach
+- Plus, a growing ecosystem of [open source plugins](https://github.com/spotify/backstage/tree/master/plugins) that further expand Backstage’s customizability and functionality
+
+For more information go to [backstage.io](https://backstage.io) or join our [Discord chatroom](https://discord.gg/EBHEGzX).
## Project roadmap
diff --git a/app-config.yaml b/app-config.yaml
index f578fb3fca..5a5fdc1cab 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -26,6 +26,11 @@ techdocs:
sentry:
organization: spotify
+newrelic:
+ api:
+ baseUrl: 'https://api.newrelic.com/v2'
+ key: NEW_RELIC_REST_API_KEY
+
auth:
providers:
google:
diff --git a/docs/README.md b/docs/README.md
index 2bda6a5aaa..cdbfbc5578 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -43,11 +43,7 @@ better yet, a pull request.
- [Overview](features/techdocs/README.md)
- [Getting Started](features/techdocs/getting-started.md)
- [Concepts](features/techdocs/concepts.md)
- - [Reading Documentation](features/techdocs/reading-documentation.md)
- - [Writing Documentation](features/techdocs/writing-documentation.md)
- - [Publishing Documentation](features/techdocs/publishing-documentation.md)
- - [Contributing](features/techdocs/contributing.md)
- - [Debugging](features/techdocs/debugging.md)
+ - [Creating and Publishing Documentation](features/techdocs/creating-and-publishing.md)
- [FAQ](features/techdocs/FAQ.md)
- Plugins
- [Overview](plugins/index.md)
diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md
index 4925f32e1a..d4d9bf1e2d 100644
--- a/docs/features/software-catalog/index.md
+++ b/docs/features/software-catalog/index.md
@@ -24,3 +24,7 @@ can be organised around the entities in the catalog.
TODO

+
+## Links
+
+- [[Blog post] Backstage Service Catalog released in alpha](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha)
diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md
index d054483482..8d0fb01ec3 100644
--- a/docs/features/techdocs/README.md
+++ b/docs/features/techdocs/README.md
@@ -26,12 +26,15 @@ Spotify’s developer experience offering with 2,400+ documentation sites and
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [TechDocs V.0 ✅][v0] | Read docs in Backstage - Enable anyone to get a reader experience working in Backstage. [See V.0 Use Cases.](./#techdocs-v0) |
| [TechDocs V.1 🚧][v1] | TechDocs end to end (alpha) - Alpha of TechDocs that you can use end to end - and contribute to. [See V.1 Use Cases.](./#techdocs-v1) |
-| [TechDocs V.2 🔮⌛][v2] | Widget Architecture - TechDocs widget architecture available, so the community can create their own customized features. |
+| [TechDocs V.2 🔮⌛][v2] | Platform stability and compatibility improvements. [See V.2 Use Cases.](./#techdocs-v2) |
+| TechDocs V.3 🔮⌛ | Widget Architecture - TechDocs widget architecture available, so the community can create their own customized features. |
[v0]: https://github.com/spotify/backstage/milestone/15
[v1]: https://github.com/spotify/backstage/milestone/16
[v2]: https://github.com/spotify/backstage/milestone/17
+
+
## Use Cases
#### TechDocs V.0
@@ -56,6 +59,14 @@ Spotify’s developer experience offering with 2,400+ documentation sites and
#### TechDocs V.2
+Platform stability and compatibility improvements
+
+- As a user I can define the metadata generated for my documentation.
+- As a user I will be able to browse metadata from within my documentation in
+ Backstage.
+
+#### TechDocs V.3
+
more to come...
## Structure
diff --git a/docs/overview/what-is-backstage.md b/docs/overview/what-is-backstage.md
index 2c6d5d9386..ad4d828d00 100644
--- a/docs/overview/what-is-backstage.md
+++ b/docs/overview/what-is-backstage.md
@@ -3,34 +3,34 @@ id: what-is-backstage
title: What is Backstage?
---
-# [Backstage](https://backstage.io)
-
-
+
[Backstage](https://backstage.io/) is an open platform for building developer
-portals. It’s based on the developer portal we’ve been using internally at
-Spotify for over four years. Backstage can be as simple as a services catalog or
-as powerful as the UX layer for your entire tech infrastructure.
+portals. Powered by a centralized service catalog, Backstage restores order to
+your microservices and infrastructure. So your product teams can ship
+high-quality code quickly — without compromising autonomy.
+
+Backstage unifies all your infrastructure tooling, services, and documentation
+to create a streamlined development environment from end to end.
+
+Out of the box, Backstage includes:
+
+- [Backstage Service Catalog](https://github.com/spotify/backstage/blob/master/docs/features/software-catalog/index.md)
+ for managing all your software (microservices, libraries, data pipelines,
+ websites, ML models, etc.)
+- [Backstage Software Templates](https://github.com/spotify/backstage/blob/master/docs/features/software-templates/index.md)
+ for quickly spinning up new projects and standardizing your tooling with your
+ organization’s best practices
+- [Backstage TechDocs](https://github.com/spotify/backstage/tree/master/docs/features/techdocs)
+ for making it easy to create, maintain, find, and use technical documentation,
+ using a "docs like code" approach
+- Plus, a growing ecosystem of
+ [open source plugins](https://github.com/spotify/backstage/tree/master/plugins)
+ that further expand Backstage’s customizability and functionality
For more information go to [backstage.io](https://backstage.io) or join our
[Discord chatroom](https://discord.gg/EBHEGzX).
-### Features
-
-- Create and manage all of your organization’s software and microservices in one
- place.
-- Services catalog keeps track of all software and its ownership.
-- Visualizations provide information about your backend services and tooling,
- and help you monitor them.
-- A unified method for managing microservices offers both visibility and
- control.
-- Preset templates allow engineers to quickly create microservices in a
- standardized way
- ([coming soon](https://github.com/spotify/backstage/milestone/11)).
-- Centralized, full-featured technical documentation with integrated tooling
- that makes it easy for developers to set up, publish, and maintain alongside
- their code ([coming soon](https://github.com/spotify/backstage/milestone/15)).
-
### Benefits
- For _engineering managers_, it allows you to maintain standards and best
diff --git a/docs/verify-links.js b/docs/verify-links.js
new file mode 100755
index 0000000000..8c865309f9
--- /dev/null
+++ b/docs/verify-links.js
@@ -0,0 +1,89 @@
+#!/usr/bin/env node
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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.
+ */
+
+const { resolve: resolvePath, dirname } = require('path');
+const fs = require('fs-extra');
+const fetch = require('node-fetch');
+const recursive = require('recursive-readdir');
+
+const projectRoot = resolvePath(__dirname, '..');
+
+async function verifyUrl(basePath, url) {
+ url = url.replace(/#.*$/, '');
+ url = url.replace(
+ /https:\/\/github.com\/spotify\/backstage\/(tree|blob)\/master/,
+ '',
+ );
+ if (!url) {
+ return;
+ }
+
+ // Only verify existence of local files for now, so skip anything with a schema
+ if (!url.match(/[a-z]+:/)) {
+ const path = url.startsWith('/')
+ ? resolvePath(projectRoot, `.${url}`)
+ : resolvePath(dirname(resolvePath(projectRoot, basePath)), url);
+ const exists = await fs.pathExists(path);
+ if (!exists) {
+ return { url, basePath };
+ }
+ }
+
+ return;
+}
+
+async function verifyFile(filePath) {
+ const content = await fs.readFile(filePath, 'utf8');
+ const mdLinks = content.match(/\[.+?\]\(.+?\)/g) || [];
+ const badUrls = [];
+
+ for (const mdLink of mdLinks) {
+ const url = mdLink.match(/\[.+\]\((.+)\)/)[1].trim();
+ const badUrl = await verifyUrl(filePath, url);
+ if (badUrl) {
+ badUrls.push(badUrl);
+ }
+ }
+
+ return badUrls;
+}
+
+async function main() {
+ process.chdir(projectRoot);
+
+ const files = await recursive('.', ['node_modules', 'dist', 'bin']);
+ const mdFiles = files.filter(f => f.endsWith('.md'));
+ const badUrls = [];
+
+ for (const mdFile of mdFiles) {
+ const badFileUrls = await verifyFile(mdFile);
+ badUrls.push(...badFileUrls);
+ }
+
+ if (badUrls.length) {
+ console.log(`Found ${badUrls.length} bad links within repo`);
+ for (const { url, basePath } of badUrls) {
+ console.error(`Unable to reach ${url}, linked from ${basePath}`);
+ }
+ process.exit(1);
+ }
+}
+
+main().catch(error => {
+ console.error(error.stack);
+ process.exit(1);
+});
diff --git a/packages/app/package.json b/packages/app/package.json
index 99865a4216..41fcc054a3 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -12,6 +12,7 @@
"@backstage/plugin-gitops-profiles": "^0.1.1-alpha.18",
"@backstage/plugin-graphiql": "^0.1.1-alpha.18",
"@backstage/plugin-lighthouse": "^0.1.1-alpha.18",
+ "@backstage/plugin-newrelic": "^0.1.1-alpha.18",
"@backstage/plugin-register-component": "^0.1.1-alpha.18",
"@backstage/plugin-rollbar": "^0.1.1-alpha.18",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.18",
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 9a9fdfe5c4..993fd77978 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -33,7 +33,12 @@ const app = createApp({
components: {
SignInPage: props => {
return (
-
+
);
},
},
diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts
index 46c8f23ef0..95d9e6c557 100644
--- a/packages/app/src/plugins.ts
+++ b/packages/app/src/plugins.ts
@@ -27,3 +27,4 @@ export { plugin as TechDocs } from '@backstage/plugin-techdocs';
export { plugin as GraphiQL } from '@backstage/plugin-graphiql';
export { plugin as GithubActions } from '@backstage/plugin-github-actions';
export { plugin as Rollbar } from '@backstage/plugin-rollbar';
+export { plugin as Newrelic } from '@backstage/plugin-newrelic';
diff --git a/packages/cli/src/commands/config/print.ts b/packages/cli/src/commands/config/print.ts
new file mode 100644
index 0000000000..bb626f520f
--- /dev/null
+++ b/packages/cli/src/commands/config/print.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { Command } from 'commander';
+import { loadConfig } from '@backstage/config-loader';
+import { ConfigReader } from '@backstage/config';
+import { paths } from '../../lib/paths';
+import { stringify as stringifyYaml } from 'yaml';
+
+export default async (cmd: Command) => {
+ const appConfigs = await loadConfig({
+ env: cmd.env ?? process.env.NODE_ENV ?? 'development',
+ shouldReadSecrets: cmd.withSecrets ?? false,
+ rootPaths: [paths.targetRoot, paths.targetDir],
+ });
+
+ const flatConfig = ConfigReader.fromConfigs(appConfigs).get();
+
+ if (cmd.format === 'json') {
+ process.stdout.write(`${JSON.stringify(flatConfig, null, 2)}\n`);
+ } else {
+ process.stdout.write(`${stringifyYaml(flatConfig)}\n`);
+ }
+};
diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts
index 3123cda613..4b9dc4bab7 100644
--- a/packages/cli/src/index.ts
+++ b/packages/cli/src/index.ts
@@ -124,6 +124,20 @@ const main = (argv: string[]) => {
.description('Run tests, forwarding args to Jest, defaulting to watch mode')
.action(lazyAction(() => import('./commands/testCommand'), 'default'));
+ program
+ .command('config:print')
+ .option('--with-secrets', 'Include secrets in the printed configuration')
+ .option(
+ '--env ',
+ 'The environment to print configuration for [NODE_ENV or development]',
+ )
+ .option(
+ '--format ',
+ 'Format to print the configuration in, either json or yaml [yaml]',
+ )
+ .description('Print the app configuration for the current package')
+ .action(lazyAction(() => import('./commands/config/print'), 'default'));
+
program
.command('prepack')
.description('Prepares a package for packaging before publishing')
diff --git a/packages/cli/templates/default-plugin/README.md.hbs b/packages/cli/templates/default-plugin/README.md.hbs
index d6f2d65134..6d68ca8250 100644
--- a/packages/cli/templates/default-plugin/README.md.hbs
+++ b/packages/cli/templates/default-plugin/README.md.hbs
@@ -10,4 +10,4 @@ Your plugin has been added to the example app in this repository, meaning you'll
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
-It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
diff --git a/packages/core/src/layout/ContentHeader/ContentHeader.tsx b/packages/core/src/layout/ContentHeader/ContentHeader.tsx
index 691c7d11f7..4652e04cdf 100644
--- a/packages/core/src/layout/ContentHeader/ContentHeader.tsx
+++ b/packages/core/src/layout/ContentHeader/ContentHeader.tsx
@@ -22,38 +22,40 @@ import React, { ComponentType, Fragment, FC } from 'react';
import { Typography, makeStyles } from '@material-ui/core';
import { Helmet } from 'react-helmet';
-const useStyles = makeStyles(theme => ({
- container: {
- width: '100%',
- display: 'flex',
- flexDirection: 'row',
- flexWrap: 'wrap',
- justifyContent: 'flex-end',
- alignItems: 'center',
- marginBottom: theme.spacing(1),
- },
- leftItemsBox: {
- flex: '1 1 auto',
- marginBottom: theme.spacing(1),
- minWidth: 0,
- overflow: 'visible',
- },
- rightItemsBox: {
- flex: '0 1 auto',
- display: 'flex',
- flexDirection: 'row',
- flexWrap: 'wrap',
- alignItems: 'center',
- marginLeft: theme.spacing(1),
- marginBottom: theme.spacing(1),
- minWidth: 0,
- overflow: 'visible',
- },
- description: {},
- title: {
- display: 'inline-flex',
- },
-}));
+const useStyles = (props: ContentHeaderProps) =>
+ makeStyles(theme => ({
+ container: {
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ justifyContent: 'flex-end',
+ alignItems: 'center',
+ marginBottom: theme.spacing(1),
+ textAlign: props.textAlign,
+ },
+ leftItemsBox: {
+ flex: '1 1 auto',
+ marginBottom: theme.spacing(1),
+ minWidth: 0,
+ overflow: 'visible',
+ },
+ rightItemsBox: {
+ flex: '0 1 auto',
+ display: 'flex',
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ alignItems: 'center',
+ marginLeft: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ minWidth: 0,
+ overflow: 'visible',
+ },
+ description: {},
+ title: {
+ display: 'inline-flex',
+ },
+ }));
type DefaultTitleProps = {
title?: string;
@@ -73,6 +75,7 @@ type ContentHeaderProps = {
title?: DefaultTitleProps['title'];
titleComponent?: ComponentType;
description?: string;
+ textAlign?: 'left' | 'right' | 'center';
};
export const ContentHeader: FC = ({
@@ -80,8 +83,9 @@ export const ContentHeader: FC = ({
title,
titleComponent: TitleComponent = undefined,
children,
+ textAlign = 'left',
}) => {
- const classes = useStyles();
+ const classes = useStyles({ textAlign })();
const renderedTitle = TitleComponent ? (
diff --git a/packages/core/src/layout/InfoCard/InfoCard.tsx b/packages/core/src/layout/InfoCard/InfoCard.tsx
index 04736b64cd..86e9c79ced 100644
--- a/packages/core/src/layout/InfoCard/InfoCard.tsx
+++ b/packages/core/src/layout/InfoCard/InfoCard.tsx
@@ -60,6 +60,8 @@ const VARIANT_STYLES = {
flexDirection: 'column',
},
fullHeight: {
+ display: 'flex',
+ flexDirection: 'column',
height: '100%',
},
height100: {
@@ -84,10 +86,10 @@ const VARIANT_STYLES = {
},
cardContent: {
fullHeight: {
- height: 'calc(100% - 50px)',
+ flex: 1,
},
height100: {
- height: 'calc(100% - 50px)',
+ flex: 1,
},
contentRow: {
display: 'flex',
diff --git a/packages/core/src/layout/SignInPage/SignInPage.tsx b/packages/core/src/layout/SignInPage/SignInPage.tsx
index 52a27f190e..8a1ff68250 100644
--- a/packages/core/src/layout/SignInPage/SignInPage.tsx
+++ b/packages/core/src/layout/SignInPage/SignInPage.tsx
@@ -24,13 +24,22 @@ import { SignInPageProps, useApi, configApiRef } from '@backstage/core-api';
import { useSignInProviders, getSignInProviders } from './providers';
import { IdentityProviders } from './types';
import { Progress } from '../../components/Progress';
+import { useStyles } from './styles';
export type Props = SignInPageProps & {
providers: IdentityProviders;
+ title?: string;
+ align?: 'center' | 'left';
};
-export const SignInPage: FC = ({ onResult, providers = [] }) => {
+export const SignInPage: FC = ({
+ onResult,
+ providers = [],
+ title,
+ align = 'left',
+}) => {
const configApi = useApi(configApiRef);
+ const classes = useStyles();
const signInProviders = getSignInProviders(providers);
const [loading, providerElements] = useSignInProviders(
@@ -46,8 +55,16 @@ export const SignInPage: FC = ({ onResult, providers = [] }) => {
-
- {providerElements}
+ {title && }
+
+ {providerElements}
+
);
diff --git a/packages/core/src/layout/SignInPage/commonProvider.tsx b/packages/core/src/layout/SignInPage/commonProvider.tsx
index f9611342a2..de9452a850 100644
--- a/packages/core/src/layout/SignInPage/commonProvider.tsx
+++ b/packages/core/src/layout/SignInPage/commonProvider.tsx
@@ -15,7 +15,7 @@
*/
import React from 'react';
-import { Grid, Typography, Button } from '@material-ui/core';
+import { Typography, Button } from '@material-ui/core';
import { InfoCard } from '../InfoCard/InfoCard';
import {
ProviderComponent,
@@ -24,6 +24,7 @@ import {
SignInConfig,
} from './types';
import { useApi, errorApiRef } from '@backstage/core-api';
+import { GridItem } from './styles';
const Component: ProviderComponent = ({ config, onResult }) => {
const { apiRef, title, message } = config as SignInConfig;
@@ -53,8 +54,9 @@ const Component: ProviderComponent = ({ config, onResult }) => {
};
return (
-
+
@@ -64,7 +66,7 @@ const Component: ProviderComponent = ({ config, onResult }) => {
>
{message}
-
+
);
};
diff --git a/packages/core/src/layout/SignInPage/customProvider.tsx b/packages/core/src/layout/SignInPage/customProvider.tsx
index c6cb9b789d..d3a292ce87 100644
--- a/packages/core/src/layout/SignInPage/customProvider.tsx
+++ b/packages/core/src/layout/SignInPage/customProvider.tsx
@@ -17,7 +17,6 @@
import React from 'react';
import { useForm } from 'react-hook-form';
import {
- Grid,
Typography,
Button,
FormControl,
@@ -28,6 +27,7 @@ import {
import isEmpty from 'lodash/isEmpty';
import { InfoCard } from '../InfoCard/InfoCard';
import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
+import { GridItem } from './styles';
const ID_TOKEN_REGEX = /^[a-z0-9+/]+\.[a-z0-9+/]+\.[a-z0-9+/]+$/i;
@@ -64,8 +64,8 @@ const Component: ProviderComponent = ({ onResult }) => {
};
return (
-
-
+
+
Enter your own User ID and credentials.
@@ -115,7 +115,7 @@ const Component: ProviderComponent = ({ onResult }) => {
-
+
);
};
diff --git a/packages/core/src/layout/SignInPage/guestProvider.tsx b/packages/core/src/layout/SignInPage/guestProvider.tsx
index 85784eb205..f4854311ac 100644
--- a/packages/core/src/layout/SignInPage/guestProvider.tsx
+++ b/packages/core/src/layout/SignInPage/guestProvider.tsx
@@ -15,8 +15,9 @@
*/
import React from 'react';
-import { Grid, Typography, Button } from '@material-ui/core';
+import { Typography, Button } from '@material-ui/core';
import { InfoCard } from '../InfoCard/InfoCard';
+import { GridItem } from './styles';
import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
const result = {
@@ -28,9 +29,10 @@ const result = {
};
const Component: ProviderComponent = ({ onResult }) => (
-
+
(
meaning some features might be unavailable.
-
+
);
const loader: ProviderLoader = async () => {
diff --git a/packages/core/src/layout/SignInPage/styles.tsx b/packages/core/src/layout/SignInPage/styles.tsx
new file mode 100644
index 0000000000..0d8bd245c5
--- /dev/null
+++ b/packages/core/src/layout/SignInPage/styles.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { Grid, makeStyles } from '@material-ui/core';
+
+export const useStyles = makeStyles({
+ container: {
+ padding: 0,
+ listStyle: 'none',
+ },
+ item: {
+ display: 'flex',
+ flexDirection: 'column',
+ width: '100%',
+ maxWidth: '400px',
+ margin: 0,
+ padding: 0,
+ },
+});
+
+export const GridItem = ({ children }: { children: JSX.Element }) => {
+ const classes = useStyles();
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/plugins/README.md b/plugins/README.md
index 50f4395bd9..a7fe648bf7 100644
--- a/plugins/README.md
+++ b/plugins/README.md
@@ -2,7 +2,7 @@
Backstage is a single-page application composed of a set of plugins.
-Our goal for the plugin ecosystem is that the definition of a plugin is flexible enough to allow you to expose pretty much any kind of infrastructure or software development tool as a plugin in Backstage. By following strong [design guidelines](https://github.com/spotify/backstage/blob/master/docs/design.md) we ensure the the overall user experience stays consistent between plugins.
+Our goal for the plugin ecosystem is that the definition of a plugin is flexible enough to allow you to expose pretty much any kind of infrastructure or software development tool as a plugin in Backstage. By following strong [design guidelines](https://github.com/spotify/backstage/blob/master/docs/dls/design.md) we ensure the the overall user experience stays consistent between plugins.

diff --git a/plugins/explore/src/components/ExplorePluginPage.tsx b/plugins/explore/src/components/ExplorePluginPage.tsx
index 1752f402be..3e073ad322 100644
--- a/plugins/explore/src/components/ExplorePluginPage.tsx
+++ b/plugins/explore/src/components/ExplorePluginPage.tsx
@@ -37,6 +37,14 @@ const useStyles = makeStyles(theme => ({
}));
const toolsCards = [
+ {
+ title: 'New Relic',
+ description:
+ 'Observability platform built to help engineers create and monitor their software',
+ url: '/newrelic',
+ image: 'https://i.imgur.com/L37ikrX.jpg',
+ tags: ['newrelic', 'performance', 'monitoring', 'errors', 'alerting'],
+ },
{
title: 'CircleCI',
description:
diff --git a/plugins/gitops-profiles/README.md b/plugins/gitops-profiles/README.md
index d083c97b84..472ea3cc4e 100644
--- a/plugins/gitops-profiles/README.md
+++ b/plugins/gitops-profiles/README.md
@@ -11,7 +11,7 @@ Your plugin has been added to the example app in this repository, meaning you'll
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
-It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
## Use GitOps-API backend with Backstage
diff --git a/plugins/graphql/README.md b/plugins/graphql/README.md
index 3f85ec766e..ae58396880 100644
--- a/plugins/graphql/README.md
+++ b/plugins/graphql/README.md
@@ -1,13 +1,28 @@
-# graphql
+# GraphQL Backend
-Welcome to the graphql backend plugin!
+## Getting Started
-_This plugin was created through the Backstage CLI_
+This backend plugin can be started in a standalone mode from directly in this package
+with `yarn start`. However, it will have limited functionality and that process is
+most convenient when developing the plugin itself.
-## Getting started
+To run it within the backend do:
-Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/graphql](http://localhost:3000/graphql).
+1. Register the router in `packages/backend/src/index.ts`:
-You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
-This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
-It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+```ts
+const graphqlEnv = useHotMemoize(module, () => createEnv('graphql'));
+
+const service = createServiceBuilder(module)
+ .loadConfig(configReader)
+ /** several different routers */
+ .addRouter('/graphql', await graphql(graphqlEnv));
+```
+
+2. Start the backend
+
+```bash
+yarn workspace example-backend start
+```
+
+This will launch the full example backend.
diff --git a/plugins/newrelic/.eslintrc.js b/plugins/newrelic/.eslintrc.js
new file mode 100644
index 0000000000..13573efa9c
--- /dev/null
+++ b/plugins/newrelic/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: [require.resolve('@backstage/cli/config/eslint')],
+};
diff --git a/plugins/newrelic/README.md b/plugins/newrelic/README.md
new file mode 100644
index 0000000000..032d4f035b
--- /dev/null
+++ b/plugins/newrelic/README.md
@@ -0,0 +1,39 @@
+# New Relic Plugin (Alpha)
+
+Website: [https://newrelic.com](https://newrelic.com)
+
+
+
+
+## Getting Started
+
+Add New Relic REST API Key to `app-config.yaml`
+
+```yaml
+newrelic:
+ api:
+ baseUrl: 'https://api.newrelic.com/v2'
+ key:
+```
+
+New Relic Plugin Path: [/newrelic](http://localhost:3000/newrelic)
+
+## Features
+
+- View New Relic Application Performance Monitoring (APM) data such as:
+ - Application Name
+ - Response Time (ms)
+ - Throughput (rpm)
+ - Error Rate
+ - Instance Count
+ - Apdex Score
+
+## Limitations
+
+- Currently only supports New Relic APM data
+
+---
+
+You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
+This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
+It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
diff --git a/plugins/newrelic/dev/index.tsx b/plugins/newrelic/dev/index.tsx
new file mode 100644
index 0000000000..812a5585d4
--- /dev/null
+++ b/plugins/newrelic/dev/index.tsx
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { createDevApp } from '@backstage/dev-utils';
+import { plugin } from '../src/plugin';
+
+createDevApp().registerPlugin(plugin).render();
diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json
new file mode 100644
index 0000000000..5b1b5d54ce
--- /dev/null
+++ b/plugins/newrelic/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@backstage/plugin-newrelic",
+ "version": "0.1.1-alpha.18",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "private": true,
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "scripts": {
+ "build": "backstage-cli plugin:build",
+ "start": "backstage-cli plugin:serve",
+ "lint": "backstage-cli lint",
+ "test": "backstage-cli test",
+ "diff": "backstage-cli plugin:diff",
+ "prepack": "backstage-cli prepack",
+ "postpack": "backstage-cli postpack",
+ "clean": "backstage-cli clean"
+ },
+ "dependencies": {
+ "@backstage/core": "^0.1.1-alpha.18",
+ "@backstage/theme": "^0.1.1-alpha.18",
+ "@material-ui/core": "^4.9.1",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.45",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1",
+ "react-use": "^15.3.3"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.1.1-alpha.18",
+ "@backstage/dev-utils": "^0.1.1-alpha.18",
+ "@testing-library/jest-dom": "^5.10.1",
+ "@testing-library/react": "^10.4.1",
+ "@testing-library/user-event": "^12.0.7",
+ "@types/jest": "^26.0.7",
+ "@types/node": "^12.0.0",
+ "jest-fetch-mock": "^3.0.3"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/newrelic/src/assets/img/newrelic-plugin-apm.png b/plugins/newrelic/src/assets/img/newrelic-plugin-apm.png
new file mode 100644
index 0000000000..cc63306bba
Binary files /dev/null and b/plugins/newrelic/src/assets/img/newrelic-plugin-apm.png differ
diff --git a/plugins/newrelic/src/assets/img/newrelic-plugin-tools.png b/plugins/newrelic/src/assets/img/newrelic-plugin-tools.png
new file mode 100644
index 0000000000..e42013f14c
Binary files /dev/null and b/plugins/newrelic/src/assets/img/newrelic-plugin-tools.png differ
diff --git a/plugins/newrelic/src/assets/img/newrelic.jpg b/plugins/newrelic/src/assets/img/newrelic.jpg
new file mode 100644
index 0000000000..d4b3a0e196
Binary files /dev/null and b/plugins/newrelic/src/assets/img/newrelic.jpg differ
diff --git a/plugins/newrelic/src/components/NewRelicComponent/NewRelicComponent.tsx b/plugins/newrelic/src/components/NewRelicComponent/NewRelicComponent.tsx
new file mode 100644
index 0000000000..94d5c530a1
--- /dev/null
+++ b/plugins/newrelic/src/components/NewRelicComponent/NewRelicComponent.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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, { FC } from 'react';
+import { Grid } from '@material-ui/core';
+import {
+ Header,
+ Page,
+ pageTheme,
+ Content,
+ ContentHeader,
+ HeaderLabel,
+ SupportButton,
+} from '@backstage/core';
+import NewRelicFetchComponent from '../NewRelicFetchComponent';
+
+const NewRelicComponent: FC<{}> = () => (
+
+
+
+
+
+ New Relic Application Performance Monitoring
+
+
+
+
+
+
+
+
+
+);
+
+export default NewRelicComponent;
diff --git a/plugins/newrelic/src/components/NewRelicComponent/index.ts b/plugins/newrelic/src/components/NewRelicComponent/index.ts
new file mode 100644
index 0000000000..de10a42770
--- /dev/null
+++ b/plugins/newrelic/src/components/NewRelicComponent/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { default } from './NewRelicComponent';
diff --git a/plugins/newrelic/src/components/NewRelicFetchComponent/NewRelicFetchComponent.tsx b/plugins/newrelic/src/components/NewRelicFetchComponent/NewRelicFetchComponent.tsx
new file mode 100644
index 0000000000..9b3791e062
--- /dev/null
+++ b/plugins/newrelic/src/components/NewRelicFetchComponent/NewRelicFetchComponent.tsx
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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, { FC } from 'react';
+import {
+ configApiRef,
+ Progress,
+ Table,
+ TableColumn,
+ useApi,
+} from '@backstage/core';
+import Alert from '@material-ui/lab/Alert';
+import { useAsync } from 'react-use';
+
+type NewRelicApplication = {
+ id: number;
+ application_summary: NewRelicApplicationSummary;
+ name: string;
+ language: string;
+ health_status: string;
+ reporting: boolean;
+ settings: NewRelicApplicationSettings;
+ links?: NewRelicApplicationLinks;
+};
+
+type NewRelicApplicationSummary = {
+ apdex_score: number;
+ error_rate: number;
+ host_count: number;
+ instance_count: number;
+ response_time: number;
+ throughput: number;
+};
+
+type NewRelicApplicationSettings = {
+ app_apdex_threshold: number;
+ end_user_apdex_threshold: number;
+ enable_real_user_monitoring: boolean;
+ use_server_side_config: boolean;
+};
+
+type NewRelicApplicationLinks = {
+ application_instances: Array;
+ servers: Array;
+ application_hosts: Array;
+};
+
+type NewRelicApplications = {
+ applications: NewRelicApplication[];
+};
+
+export const NewRelicAPMTable: FC = ({
+ applications,
+}) => {
+ const columns: TableColumn[] = [
+ { title: 'Application', field: 'name' },
+ { title: 'Response Time', field: 'responseTime' },
+ { title: 'Throughput', field: 'throughput' },
+ { title: 'Error Rate', field: 'errorRate' },
+ { title: 'Instance Count', field: 'instanceCount' },
+ { title: 'Apdex', field: 'apdexScore' },
+ ];
+ const data = applications.map((app: NewRelicApplication) => {
+ const { name, application_summary: applicationSummary } = app;
+ const {
+ response_time: responseTime,
+ throughput,
+ error_rate: errorRate,
+ instance_count: instanceCount,
+ apdex_score: apdexScore,
+ } = applicationSummary;
+
+ return {
+ name,
+ responseTime: `${responseTime} ms`,
+ throughput: `${throughput} rpm`,
+ errorRate: `${errorRate}%`,
+ instanceCount,
+ apdexScore,
+ };
+ });
+
+ return (
+
+ );
+};
+
+const NewRelicFetchComponent: FC<{}> = () => {
+ const configApi = useApi(configApiRef);
+ const apiBaseUrl = configApi.getString('newrelic.api.baseUrl');
+ const apiKey = configApi.getString('newrelic.api.key');
+
+ const { value, loading, error } = useAsync(async (): Promise<
+ NewRelicApplication[]
+ > => {
+ const response = await fetch(`${apiBaseUrl}/applications.json`, {
+ headers: {
+ 'X-Api-Key': apiKey,
+ },
+ });
+ const data: NewRelicApplications = await response.json();
+ return data.applications.filter((application: NewRelicApplication) => {
+ return application.hasOwnProperty('application_summary');
+ });
+ }, []);
+
+ if (loading) {
+ return ;
+ } else if (error) {
+ return {error.message};
+ }
+
+ return ;
+};
+
+export default NewRelicFetchComponent;
diff --git a/plugins/newrelic/src/components/NewRelicFetchComponent/index.ts b/plugins/newrelic/src/components/NewRelicFetchComponent/index.ts
new file mode 100644
index 0000000000..1907c0bf1d
--- /dev/null
+++ b/plugins/newrelic/src/components/NewRelicFetchComponent/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { default } from './NewRelicFetchComponent';
diff --git a/plugins/newrelic/src/index.ts b/plugins/newrelic/src/index.ts
new file mode 100644
index 0000000000..3a0a0fe2d3
--- /dev/null
+++ b/plugins/newrelic/src/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { plugin } from './plugin';
diff --git a/plugins/newrelic/src/plugin.test.ts b/plugins/newrelic/src/plugin.test.ts
new file mode 100644
index 0000000000..17429a95e0
--- /dev/null
+++ b/plugins/newrelic/src/plugin.test.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { plugin } from './plugin';
+
+describe('newrelic', () => {
+ it('should export plugin', () => {
+ expect(plugin).toBeDefined();
+ });
+});
diff --git a/plugins/newrelic/src/plugin.ts b/plugins/newrelic/src/plugin.ts
new file mode 100644
index 0000000000..21aac69e8f
--- /dev/null
+++ b/plugins/newrelic/src/plugin.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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, createRouteRef } from '@backstage/core';
+import NewRelicComponent from './components/NewRelicComponent';
+
+export const rootRouteRef = createRouteRef({
+ path: '/newrelic',
+ title: 'newrelic',
+});
+
+export const plugin = createPlugin({
+ id: 'newrelic',
+ register({ router }) {
+ router.addRoute(rootRouteRef, NewRelicComponent);
+ },
+});
diff --git a/plugins/newrelic/src/setupTests.ts b/plugins/newrelic/src/setupTests.ts
new file mode 100644
index 0000000000..8553642152
--- /dev/null
+++ b/plugins/newrelic/src/setupTests.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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';
+
+require('jest-fetch-mock').enableMocks();
diff --git a/plugins/sentry/README.md b/plugins/sentry/README.md
index cce2228094..73cca29d34 100644
--- a/plugins/sentry/README.md
+++ b/plugins/sentry/README.md
@@ -10,7 +10,7 @@ Your plugin has been added to the example app in this repository, meaning you'll
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
-It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
Needs SENTRY_TOKEN set in the environment for the backend to startup
diff --git a/plugins/techdocs/README.md b/plugins/techdocs/README.md
index b763679a1c..4a92c814a1 100644
--- a/plugins/techdocs/README.md
+++ b/plugins/techdocs/README.md
@@ -4,17 +4,13 @@ Welcome to the TechDocs plugin - Spotify's docs-like-code approach built directl
**WIP: This plugin is a work in progress. It is not ready for use yet. Follow our progress on [the Backstage Discord](https://discord.gg/MUpMjP2) under #docs-like-code or on [our GitHub Milestone](https://github.com/spotify/backstage/milestone/15).**
-## Sections
-
-- [MkDocs](./mkdocs/README.md)
-
## Getting started
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/docs](http://localhost:3000/docs).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
-It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
## Configuration
diff --git a/plugins/techdocs/src/reader/README.md b/plugins/techdocs/src/reader/README.md
new file mode 100644
index 0000000000..464090415c
--- /dev/null
+++ b/plugins/techdocs/src/reader/README.md
@@ -0,0 +1 @@
+# TODO
diff --git a/plugins/techdocs/src/reader/transformers/README.md b/plugins/techdocs/src/reader/transformers/README.md
new file mode 100644
index 0000000000..464090415c
--- /dev/null
+++ b/plugins/techdocs/src/reader/transformers/README.md
@@ -0,0 +1 @@
+# TODO
diff --git a/yarn.lock b/yarn.lock
index 22030c41c0..16e13985c0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4540,9 +4540,9 @@
"@types/istanbul-lib-report" "*"
"@types/jest@*", "@types/jest@^26.0.7":
- version "26.0.7"
- resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.7.tgz#495cb1d1818c1699dbc3b8b046baf1c86ef5e324"
- integrity sha512-+x0077/LoN6MjqBcVOe1y9dpryWnfDZ+Xfo3EqGeBcfPRJlQp3Lw62RvNlWxuGv7kOEwlHriAa54updi3Jvvwg==
+ version "26.0.9"
+ resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.9.tgz#0543b57da5f0cd949c5f423a00c56c492289c989"
+ integrity sha512-k4qFfJ5AUKrWok5KYXp2EPm89b0P/KZpl7Vg4XuOTVVQEhLDBDBU3iBFrjjdgd8fLw96aAtmnwhXHl63bWeBQQ==
dependencies:
jest-diff "^25.2.1"
pretty-format "^25.2.1"
@@ -4600,9 +4600,9 @@
"@types/node" "*"
"@types/lodash@^4.14.151":
- version "4.14.155"
- resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.155.tgz#e2b4514f46a261fd11542e47519c20ebce7bc23a"
- integrity sha512-vEcX7S7aPhsBCivxMwAANQburHBtfN9RdyXFk84IJmu2Z4Hkg1tOFgaslRiEqqvoLtbCBi6ika1EMspE+NZ9Lg==
+ version "4.14.159"
+ resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.159.tgz#61089719dc6fdd9c5cb46efc827f2571d1517065"
+ integrity sha512-gF7A72f7WQN33DpqOWw9geApQPh4M3PxluMtaHxWHXEGSN12/WbcEk/eNSqWNQcQhF66VSZ06vCF94CrHwXJDg==
"@types/long@^4.0.0":
version "4.0.1"
@@ -10536,7 +10536,7 @@ file-loader@^4.2.0:
loader-utils "^1.2.3"
schema-utils "^2.5.0"
-"file-saver@github:eligrey/FileSaver.js#1.3.8":
+file-saver@eligrey/FileSaver.js#1.3.8:
version "1.3.8"
resolved "https://codeload.github.com/eligrey/FileSaver.js/tar.gz/e865e37af9f9947ddcced76b549e27dc45c1cb2e"
@@ -10942,7 +10942,7 @@ fs-extra@8.1.0, fs-extra@^8.0.1, fs-extra@^8.1.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-extra@9.0.1, fs-extra@^9.0.1:
+fs-extra@9.0.1, fs-extra@^9.0.0, fs-extra@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
@@ -10972,16 +10972,6 @@ fs-extra@^7.0.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-extra@^9.0.0:
- version "9.0.0"
- resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
- integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
- dependencies:
- at-least-node "^1.0.0"
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^1.0.0"
-
fs-minipass@^1.2.5:
version "1.2.7"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
@@ -11543,16 +11533,11 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-graceful-fs@^4.1.10, graceful-fs@^4.2.4:
+graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2:
- version "4.2.3"
- resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
- integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
-
graphiql@^1.0.0-alpha.10:
version "1.0.3"
resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.0.3.tgz#f6b5d5c417d8f1a28786d3228a69883426ba74ad"
@@ -19233,9 +19218,9 @@ rollup-plugin-image-files@^1.4.2:
rollup-pluginutils "2.4.1"
rollup-plugin-peer-deps-external@^2.2.2:
- version "2.2.2"
- resolved "https://registry.npmjs.org/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.2.tgz#506cef67fb68f41cca3ec08ca6ff7936b190f568"
- integrity sha512-XcHH4UW9exRTAf73d8rk2dw2UgF//cWbilhRI4Ni/n+t0zA1eBtohKyJROn0fxa4/+WZ5R3onAyIDiwRQL+59A==
+ version "2.2.3"
+ resolved "https://registry.npmjs.org/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.3.tgz#059a8aec1eefb48a475e9fcedc3b9e3deb521213"
+ integrity sha512-W6IePXTExGXVDAlfZbNUUrx3GxUOZP248u5n4a4ID1XZMrbQ+uGeNiEfapvdzwx0qZi5DNH/hDLiPUP+pzFIxg==
rollup-plugin-postcss@^3.1.1:
version "3.1.1"